blob: 2ca7b4427e3422337cabf91989c0f8f0e77a0b80 [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
Johan Hedberg744cf192011-11-08 20:40:14 +0200258static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200259 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
Johan Hedberg744cf192011-11-08 20:40:14 +0200272 if (hdev && cmd->index != hdev->id)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200273 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
Johan Hedberg744cf192011-11-08 20:40:14 +0200478static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
479 u16 data_len, 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);
Johan Hedberg744cf192011-11-08 20:40:14 +0200492 if (hdev)
493 hdr->index = cpu_to_le16(hdev->id);
494 else
495 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200496 hdr->len = cpu_to_le16(data_len);
497
Szymon Janc4e51eae2011-02-25 19:05:48 +0100498 if (data)
499 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200500
501 hci_send_to_sock(NULL, skb, skip_sk);
502 kfree_skb(skb);
503
504 return 0;
505}
506
Johan Hedberg053f0212011-01-26 13:07:10 +0200507static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
508{
Johan Hedberga38528f2011-01-22 06:46:43 +0200509 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200510
Johan Hedberga38528f2011-01-22 06:46:43 +0200511 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200514}
515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
517 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200518{
519 struct mgmt_mode *cp, ev;
520 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200521 int err;
522
523 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100527 if (len != sizeof(*cp))
528 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
529
Szymon Janc4e51eae2011-02-25 19:05:48 +0100530 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200531 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533
Andre Guedes8c156c32011-07-07 10:30:36 -0300534 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200535
536 if (cp->val)
537 set_bit(HCI_PAIRABLE, &hdev->flags);
538 else
539 clear_bit(HCI_PAIRABLE, &hdev->flags);
540
Szymon Janc4e51eae2011-02-25 19:05:48 +0100541 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 if (err < 0)
543 goto failed;
544
Johan Hedbergc542a062011-01-26 13:11:03 +0200545 ev.val = cp->val;
546
Johan Hedberg744cf192011-11-08 20:40:14 +0200547 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200548
549failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300550 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200551 hci_dev_put(hdev);
552
553 return err;
554}
555
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300556#define EIR_FLAGS 0x01 /* flags */
557#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
558#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
559#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
560#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
561#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
562#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
563#define EIR_NAME_SHORT 0x08 /* shortened local name */
564#define EIR_NAME_COMPLETE 0x09 /* complete local name */
565#define EIR_TX_POWER 0x0A /* transmit power level */
566#define EIR_DEVICE_ID 0x10 /* device ID */
567
568#define PNP_INFO_SVCLASS_ID 0x1200
569
570static u8 bluetooth_base_uuid[] = {
571 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
572 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573};
574
575static u16 get_uuid16(u8 *uuid128)
576{
577 u32 val;
578 int i;
579
580 for (i = 0; i < 12; i++) {
581 if (bluetooth_base_uuid[i] != uuid128[i])
582 return 0;
583 }
584
585 memcpy(&val, &uuid128[12], 4);
586
587 val = le32_to_cpu(val);
588 if (val > 0xffff)
589 return 0;
590
591 return (u16) val;
592}
593
594static void create_eir(struct hci_dev *hdev, u8 *data)
595{
596 u8 *ptr = data;
597 u16 eir_len = 0;
598 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
599 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200600 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601 size_t name_len;
602
603 name_len = strlen(hdev->dev_name);
604
605 if (name_len > 0) {
606 /* EIR Data type */
607 if (name_len > 48) {
608 name_len = 48;
609 ptr[1] = EIR_NAME_SHORT;
610 } else
611 ptr[1] = EIR_NAME_COMPLETE;
612
613 /* EIR Data length */
614 ptr[0] = name_len + 1;
615
616 memcpy(ptr + 2, hdev->dev_name, name_len);
617
618 eir_len += (name_len + 2);
619 ptr += (name_len + 2);
620 }
621
622 memset(uuid16_list, 0, sizeof(uuid16_list));
623
624 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200625 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300626 u16 uuid16;
627
628 uuid16 = get_uuid16(uuid->uuid);
629 if (uuid16 == 0)
630 return;
631
632 if (uuid16 < 0x1100)
633 continue;
634
635 if (uuid16 == PNP_INFO_SVCLASS_ID)
636 continue;
637
638 /* Stop if not enough space to put next UUID */
639 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
640 truncated = 1;
641 break;
642 }
643
644 /* Check for duplicates */
645 for (i = 0; uuid16_list[i] != 0; i++)
646 if (uuid16_list[i] == uuid16)
647 break;
648
649 if (uuid16_list[i] == 0) {
650 uuid16_list[i] = uuid16;
651 eir_len += sizeof(u16);
652 }
653 }
654
655 if (uuid16_list[0] != 0) {
656 u8 *length = ptr;
657
658 /* EIR Data type */
659 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
660
661 ptr += 2;
662 eir_len += 2;
663
664 for (i = 0; uuid16_list[i] != 0; i++) {
665 *ptr++ = (uuid16_list[i] & 0x00ff);
666 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
667 }
668
669 /* EIR Data length */
670 *length = (i * sizeof(u16)) + 1;
671 }
672}
673
674static int update_eir(struct hci_dev *hdev)
675{
676 struct hci_cp_write_eir cp;
677
678 if (!(hdev->features[6] & LMP_EXT_INQ))
679 return 0;
680
681 if (hdev->ssp_mode == 0)
682 return 0;
683
684 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
685 return 0;
686
687 memset(&cp, 0, sizeof(cp));
688
689 create_eir(hdev, cp.data);
690
691 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
692 return 0;
693
694 memcpy(hdev->eir, cp.data, sizeof(cp.data));
695
696 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
697}
698
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699static u8 get_service_classes(struct hci_dev *hdev)
700{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300701 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702 u8 val = 0;
703
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300704 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200705 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200706
707 return val;
708}
709
710static int update_class(struct hci_dev *hdev)
711{
712 u8 cod[3];
713
714 BT_DBG("%s", hdev->name);
715
716 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
717 return 0;
718
719 cod[0] = hdev->minor_class;
720 cod[1] = hdev->major_class;
721 cod[2] = get_service_classes(hdev);
722
723 if (memcmp(cod, hdev->dev_class, 3) == 0)
724 return 0;
725
726 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
727}
728
Szymon Janc4e51eae2011-02-25 19:05:48 +0100729static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730{
731 struct mgmt_cp_add_uuid *cp;
732 struct hci_dev *hdev;
733 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734 int err;
735
736 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100740 if (len != sizeof(*cp))
741 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
742
Szymon Janc4e51eae2011-02-25 19:05:48 +0100743 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200744 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100745 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200746
Andre Guedes8c156c32011-07-07 10:30:36 -0300747 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200748
749 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
750 if (!uuid) {
751 err = -ENOMEM;
752 goto failed;
753 }
754
755 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200756 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200757
758 list_add(&uuid->list, &hdev->uuids);
759
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200760 err = update_class(hdev);
761 if (err < 0)
762 goto failed;
763
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300764 err = update_eir(hdev);
765 if (err < 0)
766 goto failed;
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769
770failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300771 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200772 hci_dev_put(hdev);
773
774 return err;
775}
776
Szymon Janc4e51eae2011-02-25 19:05:48 +0100777static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778{
779 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100780 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781 struct hci_dev *hdev;
782 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 +0200783 int err, found;
784
785 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200786
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100789 if (len != sizeof(*cp))
790 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
791
Szymon Janc4e51eae2011-02-25 19:05:48 +0100792 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200793 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100794 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200795
Andre Guedes8c156c32011-07-07 10:30:36 -0300796 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200797
798 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
799 err = hci_uuids_clear(hdev);
800 goto unlock;
801 }
802
803 found = 0;
804
805 list_for_each_safe(p, n, &hdev->uuids) {
806 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
807
808 if (memcmp(match->uuid, cp->uuid, 16) != 0)
809 continue;
810
811 list_del(&match->list);
812 found++;
813 }
814
815 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100816 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200817 goto unlock;
818 }
819
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200820 err = update_class(hdev);
821 if (err < 0)
822 goto unlock;
823
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300824 err = update_eir(hdev);
825 if (err < 0)
826 goto unlock;
827
Szymon Janc4e51eae2011-02-25 19:05:48 +0100828 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200829
830unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300831 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200832 hci_dev_put(hdev);
833
834 return err;
835}
836
Szymon Janc4e51eae2011-02-25 19:05:48 +0100837static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
838 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200839{
840 struct hci_dev *hdev;
841 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842 int err;
843
844 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100848 if (len != sizeof(*cp))
849 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
850
Szymon Janc4e51eae2011-02-25 19:05:48 +0100851 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200852 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100853 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200854
Andre Guedes8c156c32011-07-07 10:30:36 -0300855 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200856
857 hdev->major_class = cp->major;
858 hdev->minor_class = cp->minor;
859
860 err = update_class(hdev);
861
862 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100863 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864
Andre Guedes8c156c32011-07-07 10:30:36 -0300865 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200866 hci_dev_put(hdev);
867
868 return err;
869}
870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
872 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873{
874 struct hci_dev *hdev;
875 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876 int err;
877
878 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100880 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100881 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100882
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200884 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100885 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200886
Andre Guedes8c156c32011-07-07 10:30:36 -0300887 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200888
Szymon Janc4e51eae2011-02-25 19:05:48 +0100889 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200890
891 if (cp->enable) {
892 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
893 err = 0;
894 } else {
895 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
896 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300897 if (err == 0)
898 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899 }
900
901 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100902 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
903 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300904 else
905 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
906
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200907
Andre Guedes8c156c32011-07-07 10:30:36 -0300908 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200909 hci_dev_put(hdev);
910
911 return err;
912}
913
Johan Hedberg86742e12011-11-07 23:13:38 +0200914static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
915 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200916{
917 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200918 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100919 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300920 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200921
922 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100923
924 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200925 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100926
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200927 key_count = get_unaligned_le16(&cp->key_count);
928
Johan Hedberg86742e12011-11-07 23:13:38 +0200929 expected_len = sizeof(*cp) + key_count *
930 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300931 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200932 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300933 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200934 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935 }
936
Szymon Janc4e51eae2011-02-25 19:05:48 +0100937 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200938 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200939 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200940
Szymon Janc4e51eae2011-02-25 19:05:48 +0100941 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200942 key_count);
943
Andre Guedes8c156c32011-07-07 10:30:36 -0300944 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200945
946 hci_link_keys_clear(hdev);
947
948 set_bit(HCI_LINK_KEYS, &hdev->flags);
949
950 if (cp->debug_keys)
951 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
952 else
953 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
954
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300955 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200956 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700958 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200959 key->pin_len);
960 }
961
Andre Guedes8c156c32011-07-07 10:30:36 -0300962 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200963 hci_dev_put(hdev);
964
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300965 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200966}
967
Johan Hedberg86742e12011-11-07 23:13:38 +0200968static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
969 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200970{
971 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200972 struct mgmt_cp_remove_keys *cp;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200973 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974 int err;
975
976 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200977
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100978 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200979 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100980
Szymon Janc4e51eae2011-02-25 19:05:48 +0100981 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200982 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200983 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200984
Andre Guedes8c156c32011-07-07 10:30:36 -0300985 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200986
987 err = hci_remove_link_key(hdev, &cp->bdaddr);
988 if (err < 0) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200989 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200990 goto unlock;
991 }
992
993 err = 0;
994
995 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
996 goto unlock;
997
998 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
999 if (conn) {
1000 struct hci_cp_disconnect dc;
1001
1002 put_unaligned_le16(conn->handle, &dc.handle);
1003 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -04001004 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001005 }
1006
1007unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001008 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001009 hci_dev_put(hdev);
1010
1011 return err;
1012}
1013
Szymon Janc4e51eae2011-02-25 19:05:48 +01001014static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001015{
1016 struct hci_dev *hdev;
1017 struct mgmt_cp_disconnect *cp;
1018 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001019 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001021 int err;
1022
1023 BT_DBG("");
1024
1025 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001027 if (len != sizeof(*cp))
1028 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1029
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001031 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001032 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001033
Andre Guedes8c156c32011-07-07 10:30:36 -03001034 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001035
1036 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001037 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001038 goto failed;
1039 }
1040
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1042 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001043 goto failed;
1044 }
1045
1046 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001047 if (!conn)
1048 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1049
Johan Hedberg8962ee72011-01-20 12:40:27 +02001050 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001051 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001052 goto failed;
1053 }
1054
Szymon Janc4e51eae2011-02-25 19:05:48 +01001055 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001056 if (!cmd) {
1057 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001059 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001060
1061 put_unaligned_le16(conn->handle, &dc.handle);
1062 dc.reason = 0x13; /* Remote User Terminated Connection */
1063
1064 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1065 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001066 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001067
1068failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001069 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001070 hci_dev_put(hdev);
1071
1072 return err;
1073}
1074
Johan Hedberg4c659c32011-11-07 23:13:39 +02001075static u8 link_to_mgmt(u8 link_type)
1076{
1077 switch (link_type) {
1078 case LE_LINK:
1079 return MGMT_ADDR_LE;
1080 case ACL_LINK:
1081 return MGMT_ADDR_BREDR;
1082 default:
1083 return MGMT_ADDR_INVALID;
1084 }
1085}
1086
Szymon Janc8ce62842011-03-01 16:55:32 +01001087static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001088{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001089 struct mgmt_rp_get_connections *rp;
1090 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001091 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001092 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001093 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001094 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001095 int i, err;
1096
1097 BT_DBG("");
1098
Szymon Janc4e51eae2011-02-25 19:05:48 +01001099 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001100 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001101 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001102
Andre Guedes8c156c32011-07-07 10:30:36 -03001103 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104
1105 count = 0;
1106 list_for_each(p, &hdev->conn_hash.list) {
1107 count++;
1108 }
1109
Johan Hedberg4c659c32011-11-07 23:13:39 +02001110 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001111 rp = kmalloc(rp_len, GFP_ATOMIC);
1112 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001113 err = -ENOMEM;
1114 goto unlock;
1115 }
1116
Johan Hedberg2784eb42011-01-21 13:56:35 +02001117 put_unaligned_le16(count, &rp->conn_count);
1118
Johan Hedberg2784eb42011-01-21 13:56:35 +02001119 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001120 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1121 bacpy(&rp->addr[i].bdaddr, &c->dst);
1122 rp->addr[i].type = link_to_mgmt(c->type);
1123 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1124 continue;
1125 i++;
1126 }
1127
1128 /* Recalculate length in case of filtered SCO connections, etc */
1129 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001132
1133unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001134 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001135 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001136 hci_dev_put(hdev);
1137 return err;
1138}
1139
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001140static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1141 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1142{
1143 struct pending_cmd *cmd;
1144 int err;
1145
1146 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1147 sizeof(*cp));
1148 if (!cmd)
1149 return -ENOMEM;
1150
1151 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1152 &cp->bdaddr);
1153 if (err < 0)
1154 mgmt_pending_remove(cmd);
1155
1156 return err;
1157}
1158
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1160 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001161{
1162 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001163 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001164 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001165 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001166 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001167 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001168 int err;
1169
1170 BT_DBG("");
1171
1172 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001173
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001174 if (len != sizeof(*cp))
1175 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1176
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001178 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001180
Andre Guedes8c156c32011-07-07 10:30:36 -03001181 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182
1183 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001184 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185 goto failed;
1186 }
1187
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001188 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1189 if (!conn) {
1190 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1191 goto failed;
1192 }
1193
1194 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1195 bacpy(&ncp.bdaddr, &cp->bdaddr);
1196
1197 BT_ERR("PIN code is not 16 bytes long");
1198
1199 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1200 if (err >= 0)
1201 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1202 EINVAL);
1203
1204 goto failed;
1205 }
1206
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001208 if (!cmd) {
1209 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001211 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001212
1213 bacpy(&reply.bdaddr, &cp->bdaddr);
1214 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001215 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001216
1217 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1218 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001219 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001220
1221failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001222 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001223 hci_dev_put(hdev);
1224
1225 return err;
1226}
1227
Szymon Janc4e51eae2011-02-25 19:05:48 +01001228static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1229 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230{
1231 struct hci_dev *hdev;
1232 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001233 int err;
1234
1235 BT_DBG("");
1236
1237 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001238
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001239 if (len != sizeof(*cp))
1240 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1241 EINVAL);
1242
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001244 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1246 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001247
Andre Guedes8c156c32011-07-07 10:30:36 -03001248 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001249
1250 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001251 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1252 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001253 goto failed;
1254 }
1255
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001256 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001257
1258failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001259 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001260 hci_dev_put(hdev);
1261
1262 return err;
1263}
1264
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1266 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001267{
1268 struct hci_dev *hdev;
1269 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001270
1271 BT_DBG("");
1272
1273 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001274
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001275 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001276 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001277
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001279 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001280 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001281
Andre Guedes8c156c32011-07-07 10:30:36 -03001282 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001283
1284 hdev->io_capability = cp->io_capability;
1285
1286 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001287 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001288
Andre Guedes8c156c32011-07-07 10:30:36 -03001289 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001290 hci_dev_put(hdev);
1291
Szymon Janc4e51eae2011-02-25 19:05:48 +01001292 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001293}
1294
Johan Hedberge9a416b2011-02-19 12:05:56 -03001295static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1296{
1297 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001298 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001299
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001300 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001301 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1302 continue;
1303
1304 if (cmd->index != hdev->id)
1305 continue;
1306
1307 if (cmd->user_data != conn)
1308 continue;
1309
1310 return cmd;
1311 }
1312
1313 return NULL;
1314}
1315
1316static void pairing_complete(struct pending_cmd *cmd, u8 status)
1317{
1318 struct mgmt_rp_pair_device rp;
1319 struct hci_conn *conn = cmd->user_data;
1320
Johan Hedberge9a416b2011-02-19 12:05:56 -03001321 bacpy(&rp.bdaddr, &conn->dst);
1322 rp.status = status;
1323
Szymon Janc4e51eae2011-02-25 19:05:48 +01001324 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001325
1326 /* So we don't get further callbacks for this connection */
1327 conn->connect_cfm_cb = NULL;
1328 conn->security_cfm_cb = NULL;
1329 conn->disconn_cfm_cb = NULL;
1330
1331 hci_conn_put(conn);
1332
Johan Hedberga664b5b2011-02-19 12:06:02 -03001333 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001334}
1335
1336static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1337{
1338 struct pending_cmd *cmd;
1339
1340 BT_DBG("status %u", status);
1341
1342 cmd = find_pairing(conn);
1343 if (!cmd) {
1344 BT_DBG("Unable to find a pending command");
1345 return;
1346 }
1347
1348 pairing_complete(cmd, status);
1349}
1350
Szymon Janc4e51eae2011-02-25 19:05:48 +01001351static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352{
1353 struct hci_dev *hdev;
1354 struct mgmt_cp_pair_device *cp;
1355 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001356 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001357 u8 sec_level, auth_type;
1358 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001359 int err;
1360
1361 BT_DBG("");
1362
1363 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001364
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001365 if (len != sizeof(*cp))
1366 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1367
Szymon Janc4e51eae2011-02-25 19:05:48 +01001368 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001369 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001370 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001371
Andre Guedes8c156c32011-07-07 10:30:36 -03001372 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001374 sec_level = BT_SECURITY_MEDIUM;
1375 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001376 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001377 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001378 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001379
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001380 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1381 if (entry)
1382 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1383 auth_type);
1384 else
1385 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1386 auth_type);
1387
Ville Tervo30e76272011-02-22 16:10:53 -03001388 if (IS_ERR(conn)) {
1389 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001390 goto unlock;
1391 }
1392
1393 if (conn->connect_cfm_cb) {
1394 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001395 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001396 goto unlock;
1397 }
1398
Szymon Janc4e51eae2011-02-25 19:05:48 +01001399 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001400 if (!cmd) {
1401 err = -ENOMEM;
1402 hci_conn_put(conn);
1403 goto unlock;
1404 }
1405
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001406 /* For LE, just connecting isn't a proof that the pairing finished */
1407 if (!entry)
1408 conn->connect_cfm_cb = pairing_complete_cb;
1409
Johan Hedberge9a416b2011-02-19 12:05:56 -03001410 conn->security_cfm_cb = pairing_complete_cb;
1411 conn->disconn_cfm_cb = pairing_complete_cb;
1412 conn->io_capability = cp->io_cap;
1413 cmd->user_data = conn;
1414
1415 if (conn->state == BT_CONNECTED &&
1416 hci_conn_security(conn, sec_level, auth_type))
1417 pairing_complete(cmd, 0);
1418
1419 err = 0;
1420
1421unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001422 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001423 hci_dev_put(hdev);
1424
1425 return err;
1426}
1427
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1429 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001430{
1431 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001432 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001433 struct pending_cmd *cmd;
1434 struct hci_dev *hdev;
1435 int err;
1436
1437 BT_DBG("");
1438
Johan Hedberga5c29682011-02-19 12:05:57 -03001439 if (success) {
1440 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1441 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1442 } else {
1443 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1444 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1445 }
1446
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001447 if (len != sizeof(*cp))
1448 return cmd_status(sk, index, mgmt_op, EINVAL);
1449
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001451 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001453
Andre Guedes8c156c32011-07-07 10:30:36 -03001454 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001455
Johan Hedberga5c29682011-02-19 12:05:57 -03001456 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001458 goto failed;
1459 }
1460
Szymon Janc4e51eae2011-02-25 19:05:48 +01001461 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001462 if (!cmd) {
1463 err = -ENOMEM;
1464 goto failed;
1465 }
1466
1467 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001468 if (err < 0)
1469 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001470
1471failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001472 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001473 hci_dev_put(hdev);
1474
1475 return err;
1476}
1477
Johan Hedbergb312b1612011-03-16 14:29:37 +02001478static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1479 u16 len)
1480{
1481 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1482 struct hci_cp_write_local_name hci_cp;
1483 struct hci_dev *hdev;
1484 struct pending_cmd *cmd;
1485 int err;
1486
1487 BT_DBG("");
1488
1489 if (len != sizeof(*mgmt_cp))
1490 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1491
1492 hdev = hci_dev_get(index);
1493 if (!hdev)
1494 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1495
Andre Guedes8c156c32011-07-07 10:30:36 -03001496 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001497
1498 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1499 if (!cmd) {
1500 err = -ENOMEM;
1501 goto failed;
1502 }
1503
1504 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1505 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1506 &hci_cp);
1507 if (err < 0)
1508 mgmt_pending_remove(cmd);
1509
1510failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001511 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001512 hci_dev_put(hdev);
1513
1514 return err;
1515}
1516
Szymon Jancc35938b2011-03-22 13:12:21 +01001517static int read_local_oob_data(struct sock *sk, u16 index)
1518{
1519 struct hci_dev *hdev;
1520 struct pending_cmd *cmd;
1521 int err;
1522
1523 BT_DBG("hci%u", index);
1524
1525 hdev = hci_dev_get(index);
1526 if (!hdev)
1527 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1528 ENODEV);
1529
Andre Guedes8c156c32011-07-07 10:30:36 -03001530 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001531
1532 if (!test_bit(HCI_UP, &hdev->flags)) {
1533 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1534 ENETDOWN);
1535 goto unlock;
1536 }
1537
1538 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1539 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1540 EOPNOTSUPP);
1541 goto unlock;
1542 }
1543
1544 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1545 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1546 goto unlock;
1547 }
1548
1549 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1550 if (!cmd) {
1551 err = -ENOMEM;
1552 goto unlock;
1553 }
1554
1555 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1556 if (err < 0)
1557 mgmt_pending_remove(cmd);
1558
1559unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001560 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001561 hci_dev_put(hdev);
1562
1563 return err;
1564}
1565
Szymon Janc2763eda2011-03-22 13:12:22 +01001566static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1567 u16 len)
1568{
1569 struct hci_dev *hdev;
1570 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1571 int err;
1572
1573 BT_DBG("hci%u ", index);
1574
1575 if (len != sizeof(*cp))
1576 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1577 EINVAL);
1578
1579 hdev = hci_dev_get(index);
1580 if (!hdev)
1581 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1582 ENODEV);
1583
Andre Guedes8c156c32011-07-07 10:30:36 -03001584 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001585
1586 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1587 cp->randomizer);
1588 if (err < 0)
1589 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1590 else
1591 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1592 0);
1593
Andre Guedes8c156c32011-07-07 10:30:36 -03001594 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001595 hci_dev_put(hdev);
1596
1597 return err;
1598}
1599
1600static int remove_remote_oob_data(struct sock *sk, u16 index,
1601 unsigned char *data, u16 len)
1602{
1603 struct hci_dev *hdev;
1604 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1605 int err;
1606
1607 BT_DBG("hci%u ", index);
1608
1609 if (len != sizeof(*cp))
1610 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1611 EINVAL);
1612
1613 hdev = hci_dev_get(index);
1614 if (!hdev)
1615 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1616 ENODEV);
1617
Andre Guedes8c156c32011-07-07 10:30:36 -03001618 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001619
1620 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1621 if (err < 0)
1622 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1623 -err);
1624 else
1625 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1626 NULL, 0);
1627
Andre Guedes8c156c32011-07-07 10:30:36 -03001628 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001629 hci_dev_put(hdev);
1630
1631 return err;
1632}
1633
Johan Hedberg14a53662011-04-27 10:29:56 -04001634static int start_discovery(struct sock *sk, u16 index)
1635{
Johan Hedberg14a53662011-04-27 10:29:56 -04001636 struct pending_cmd *cmd;
1637 struct hci_dev *hdev;
1638 int err;
1639
1640 BT_DBG("hci%u", index);
1641
1642 hdev = hci_dev_get(index);
1643 if (!hdev)
1644 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1645
1646 hci_dev_lock_bh(hdev);
1647
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001648 if (!test_bit(HCI_UP, &hdev->flags)) {
1649 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1650 goto failed;
1651 }
1652
Johan Hedberg14a53662011-04-27 10:29:56 -04001653 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1654 if (!cmd) {
1655 err = -ENOMEM;
1656 goto failed;
1657 }
1658
Andre Guedes2519a1f2011-11-07 11:45:24 -03001659 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001660 if (err < 0)
1661 mgmt_pending_remove(cmd);
1662
1663failed:
1664 hci_dev_unlock_bh(hdev);
1665 hci_dev_put(hdev);
1666
1667 return err;
1668}
1669
1670static int stop_discovery(struct sock *sk, u16 index)
1671{
1672 struct hci_dev *hdev;
1673 struct pending_cmd *cmd;
1674 int err;
1675
1676 BT_DBG("hci%u", index);
1677
1678 hdev = hci_dev_get(index);
1679 if (!hdev)
1680 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1681
1682 hci_dev_lock_bh(hdev);
1683
1684 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1685 if (!cmd) {
1686 err = -ENOMEM;
1687 goto failed;
1688 }
1689
Andre Guedes023d50492011-11-04 14:16:52 -03001690 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001691 if (err < 0)
1692 mgmt_pending_remove(cmd);
1693
1694failed:
1695 hci_dev_unlock_bh(hdev);
1696 hci_dev_put(hdev);
1697
1698 return err;
1699}
1700
Antti Julku7fbec222011-06-15 12:01:15 +03001701static int block_device(struct sock *sk, u16 index, unsigned char *data,
1702 u16 len)
1703{
1704 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001705 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001706 int err;
1707
1708 BT_DBG("hci%u", index);
1709
Antti Julku7fbec222011-06-15 12:01:15 +03001710 if (len != sizeof(*cp))
1711 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1712 EINVAL);
1713
1714 hdev = hci_dev_get(index);
1715 if (!hdev)
1716 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1717 ENODEV);
1718
Antti Julku5e762442011-08-25 16:48:02 +03001719 hci_dev_lock_bh(hdev);
1720
Antti Julku7fbec222011-06-15 12:01:15 +03001721 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001722 if (err < 0)
1723 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1724 else
1725 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1726 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001727
Antti Julku5e762442011-08-25 16:48:02 +03001728 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001729 hci_dev_put(hdev);
1730
1731 return err;
1732}
1733
1734static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1735 u16 len)
1736{
1737 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001738 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001739 int err;
1740
1741 BT_DBG("hci%u", index);
1742
Antti Julku7fbec222011-06-15 12:01:15 +03001743 if (len != sizeof(*cp))
1744 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1745 EINVAL);
1746
1747 hdev = hci_dev_get(index);
1748 if (!hdev)
1749 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1750 ENODEV);
1751
Antti Julku5e762442011-08-25 16:48:02 +03001752 hci_dev_lock_bh(hdev);
1753
Antti Julku7fbec222011-06-15 12:01:15 +03001754 err = hci_blacklist_del(hdev, &cp->bdaddr);
1755
1756 if (err < 0)
1757 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1758 else
1759 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1760 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001761
Antti Julku5e762442011-08-25 16:48:02 +03001762 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001763 hci_dev_put(hdev);
1764
1765 return err;
1766}
1767
Antti Julkuf6422ec2011-06-22 13:11:56 +03001768static int set_fast_connectable(struct sock *sk, u16 index,
1769 unsigned char *data, u16 len)
1770{
1771 struct hci_dev *hdev;
1772 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1773 struct hci_cp_write_page_scan_activity acp;
1774 u8 type;
1775 int err;
1776
1777 BT_DBG("hci%u", index);
1778
1779 if (len != sizeof(*cp))
1780 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1781 EINVAL);
1782
1783 hdev = hci_dev_get(index);
1784 if (!hdev)
1785 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1786 ENODEV);
1787
1788 hci_dev_lock(hdev);
1789
1790 if (cp->enable) {
1791 type = PAGE_SCAN_TYPE_INTERLACED;
1792 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1793 } else {
1794 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1795 acp.interval = 0x0800; /* default 1.28 sec page scan */
1796 }
1797
1798 acp.window = 0x0012; /* default 11.25 msec page scan window */
1799
1800 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1801 sizeof(acp), &acp);
1802 if (err < 0) {
1803 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1804 -err);
1805 goto done;
1806 }
1807
1808 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1809 if (err < 0) {
1810 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1811 -err);
1812 goto done;
1813 }
1814
1815 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1816 NULL, 0);
1817done:
1818 hci_dev_unlock(hdev);
1819 hci_dev_put(hdev);
1820
1821 return err;
1822}
1823
Johan Hedberg03811012010-12-08 00:21:06 +02001824int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1825{
1826 unsigned char *buf;
1827 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001828 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001829 int err;
1830
1831 BT_DBG("got %zu bytes", msglen);
1832
1833 if (msglen < sizeof(*hdr))
1834 return -EINVAL;
1835
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001836 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001837 if (!buf)
1838 return -ENOMEM;
1839
1840 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1841 err = -EFAULT;
1842 goto done;
1843 }
1844
1845 hdr = (struct mgmt_hdr *) buf;
1846 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001847 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001848 len = get_unaligned_le16(&hdr->len);
1849
1850 if (len != msglen - sizeof(*hdr)) {
1851 err = -EINVAL;
1852 goto done;
1853 }
1854
1855 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001856 case MGMT_OP_READ_VERSION:
1857 err = read_version(sk);
1858 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001859 case MGMT_OP_READ_INDEX_LIST:
1860 err = read_index_list(sk);
1861 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001862 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001864 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001865 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001867 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001868 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001870 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001871 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001873 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001874 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001876 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001877 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 break;
1880 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001882 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001883 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001885 break;
1886 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001887 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001888 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001889 case MGMT_OP_LOAD_LINK_KEYS:
1890 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001892 case MGMT_OP_REMOVE_KEYS:
1893 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001895 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001897 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001898 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001899 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001900 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001901 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 break;
1904 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001906 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001908 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001909 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001911 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001913 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 break;
1916 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001917 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001918 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001919 case MGMT_OP_SET_LOCAL_NAME:
1920 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1921 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001922 case MGMT_OP_READ_LOCAL_OOB_DATA:
1923 err = read_local_oob_data(sk, index);
1924 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001925 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1926 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1927 break;
1928 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1929 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1930 len);
1931 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001932 case MGMT_OP_START_DISCOVERY:
1933 err = start_discovery(sk, index);
1934 break;
1935 case MGMT_OP_STOP_DISCOVERY:
1936 err = stop_discovery(sk, index);
1937 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001938 case MGMT_OP_BLOCK_DEVICE:
1939 err = block_device(sk, index, buf + sizeof(*hdr), len);
1940 break;
1941 case MGMT_OP_UNBLOCK_DEVICE:
1942 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1943 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001944 case MGMT_OP_SET_FAST_CONNECTABLE:
1945 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1946 len);
1947 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001948 default:
1949 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001950 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001951 break;
1952 }
1953
Johan Hedberge41d8b42010-12-13 21:07:03 +02001954 if (err < 0)
1955 goto done;
1956
Johan Hedberg03811012010-12-08 00:21:06 +02001957 err = msglen;
1958
1959done:
1960 kfree(buf);
1961 return err;
1962}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001963
Johan Hedbergb24752f2011-11-03 14:40:33 +02001964static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1965{
1966 u8 *status = data;
1967
1968 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1969 mgmt_pending_remove(cmd);
1970}
1971
Johan Hedberg744cf192011-11-08 20:40:14 +02001972int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001973{
Johan Hedberg744cf192011-11-08 20:40:14 +02001974 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001975}
1976
Johan Hedberg744cf192011-11-08 20:40:14 +02001977int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001978{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001979 u8 status = ENODEV;
1980
Johan Hedberg744cf192011-11-08 20:40:14 +02001981 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001982
Johan Hedberg744cf192011-11-08 20:40:14 +02001983 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001984}
1985
Johan Hedberg73f22f62010-12-29 16:00:25 +02001986struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001987 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001988 struct sock *sk;
1989};
1990
Johan Hedberg72a734e2010-12-30 00:38:22 +02001991static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001992{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001993 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001994 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001995
Johan Hedberg72a734e2010-12-30 00:38:22 +02001996 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001997 return;
1998
Johan Hedberg053f0212011-01-26 13:07:10 +02001999 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000
2001 list_del(&cmd->list);
2002
2003 if (match->sk == NULL) {
2004 match->sk = cmd->sk;
2005 sock_hold(match->sk);
2006 }
2007
2008 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002009}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002010
Johan Hedberg744cf192011-11-08 20:40:14 +02002011int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002012{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002013 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002014 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002016
Johan Hedberg744cf192011-11-08 20:40:14 +02002017 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002018
Johan Hedbergb24752f2011-11-03 14:40:33 +02002019 if (!powered) {
2020 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002021 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002022 }
2023
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002025
Johan Hedberg744cf192011-11-08 20:40:14 +02002026 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002027
2028 if (match.sk)
2029 sock_put(match.sk);
2030
2031 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002032}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002033
Johan Hedberg744cf192011-11-08 20:40:14 +02002034int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002035{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002037 struct cmd_lookup match = { discoverable, NULL };
2038 int ret;
2039
Johan Hedberg744cf192011-11-08 20:40:14 +02002040 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041
Johan Hedberg72a734e2010-12-30 00:38:22 +02002042 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002043
Johan Hedberg744cf192011-11-08 20:40:14 +02002044 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002045 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002046
2047 if (match.sk)
2048 sock_put(match.sk);
2049
2050 return ret;
2051}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052
Johan Hedberg744cf192011-11-08 20:40:14 +02002053int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002054{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002055 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002056 struct cmd_lookup match = { connectable, NULL };
2057 int ret;
2058
Johan Hedberg744cf192011-11-08 20:40:14 +02002059 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002060
Johan Hedberg72a734e2010-12-30 00:38:22 +02002061 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002062
Johan Hedberg744cf192011-11-08 20:40:14 +02002063 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002064
2065 if (match.sk)
2066 sock_put(match.sk);
2067
2068 return ret;
2069}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002070
Johan Hedberg744cf192011-11-08 20:40:14 +02002071int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002072{
2073 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002074 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002075 cmd_status_rsp, &status);
2076
2077 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002078 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002079 cmd_status_rsp, &status);
2080
2081 return 0;
2082}
2083
Johan Hedberg744cf192011-11-08 20:40:14 +02002084int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2085 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002086{
Johan Hedberg86742e12011-11-07 23:13:38 +02002087 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002088
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002089 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002090
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002091 ev.store_hint = persistent;
2092 bacpy(&ev.key.bdaddr, &key->bdaddr);
2093 ev.key.type = key->type;
2094 memcpy(ev.key.val, key->val, 16);
2095 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002096
Johan Hedberg744cf192011-11-08 20:40:14 +02002097 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002098}
Johan Hedbergf7520542011-01-20 12:34:39 +02002099
Johan Hedberg744cf192011-11-08 20:40:14 +02002100int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002101{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002102 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002103
Johan Hedbergf7520542011-01-20 12:34:39 +02002104 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002105 ev.type = link_to_mgmt(link_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002106
Johan Hedberg744cf192011-11-08 20:40:14 +02002107 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002108}
2109
Johan Hedberg8962ee72011-01-20 12:40:27 +02002110static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2111{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002112 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002114 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002115
Johan Hedberga38528f2011-01-22 06:46:43 +02002116 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002117
Szymon Janc4e51eae2011-02-25 19:05:48 +01002118 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002119
2120 *sk = cmd->sk;
2121 sock_hold(*sk);
2122
Johan Hedberga664b5b2011-02-19 12:06:02 -03002123 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002124}
2125
Johan Hedberg744cf192011-11-08 20:40:14 +02002126int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002127{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002128 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002129 struct sock *sk = NULL;
2130 int err;
2131
Johan Hedberg744cf192011-11-08 20:40:14 +02002132 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002133
Johan Hedbergf7520542011-01-20 12:34:39 +02002134 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002135 ev.type = link_to_mgmt(type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002136
Johan Hedberg744cf192011-11-08 20:40:14 +02002137 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002138
2139 if (sk)
2140 sock_put(sk);
2141
2142 return err;
2143}
2144
Johan Hedberg744cf192011-11-08 20:40:14 +02002145int mgmt_disconnect_failed(struct hci_dev *hdev)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002146{
2147 struct pending_cmd *cmd;
2148 int err;
2149
Johan Hedberg744cf192011-11-08 20:40:14 +02002150 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev->id);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002151 if (!cmd)
2152 return -ENOENT;
2153
Johan Hedberg744cf192011-11-08 20:40:14 +02002154 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002155
Johan Hedberga664b5b2011-02-19 12:06:02 -03002156 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002157
2158 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002159}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002160
Johan Hedberg744cf192011-11-08 20:40:14 +02002161int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2162 u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002163{
2164 struct mgmt_ev_connect_failed ev;
2165
Johan Hedberg4c659c32011-11-07 23:13:39 +02002166 bacpy(&ev.addr.bdaddr, bdaddr);
2167 ev.addr.type = link_to_mgmt(type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002168 ev.status = status;
2169
Johan Hedberg744cf192011-11-08 20:40:14 +02002170 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002171}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172
Johan Hedberg744cf192011-11-08 20:40:14 +02002173int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174{
2175 struct mgmt_ev_pin_code_request ev;
2176
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002178 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179
Johan Hedberg744cf192011-11-08 20:40:14 +02002180 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002181 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182}
2183
Johan Hedberg744cf192011-11-08 20:40:14 +02002184int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2185 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186{
2187 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002188 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189 int err;
2190
Johan Hedberg744cf192011-11-08 20:40:14 +02002191 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev->id);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002192 if (!cmd)
2193 return -ENOENT;
2194
Johan Hedbergac56fb12011-02-19 12:05:59 -03002195 bacpy(&rp.bdaddr, bdaddr);
2196 rp.status = status;
2197
Johan Hedberg744cf192011-11-08 20:40:14 +02002198 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002199 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002200
Johan Hedberga664b5b2011-02-19 12:06:02 -03002201 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202
2203 return err;
2204}
2205
Johan Hedberg744cf192011-11-08 20:40:14 +02002206int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2207 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002208{
2209 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002210 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002211 int err;
2212
Johan Hedberg744cf192011-11-08 20:40:14 +02002213 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev->id);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002214 if (!cmd)
2215 return -ENOENT;
2216
Johan Hedbergac56fb12011-02-19 12:05:59 -03002217 bacpy(&rp.bdaddr, bdaddr);
2218 rp.status = status;
2219
Johan Hedberg744cf192011-11-08 20:40:14 +02002220 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002221 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002222
Johan Hedberga664b5b2011-02-19 12:06:02 -03002223 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002224
2225 return err;
2226}
Johan Hedberga5c29682011-02-19 12:05:57 -03002227
Johan Hedberg744cf192011-11-08 20:40:14 +02002228int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2229 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002230{
2231 struct mgmt_ev_user_confirm_request ev;
2232
Johan Hedberg744cf192011-11-08 20:40:14 +02002233 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002234
Johan Hedberga5c29682011-02-19 12:05:57 -03002235 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002236 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002237 put_unaligned_le32(value, &ev.value);
2238
Johan Hedberg744cf192011-11-08 20:40:14 +02002239 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002240 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002241}
2242
Johan Hedberg744cf192011-11-08 20:40:14 +02002243static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2244 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002245{
2246 struct pending_cmd *cmd;
2247 struct mgmt_rp_user_confirm_reply rp;
2248 int err;
2249
Johan Hedberg744cf192011-11-08 20:40:14 +02002250 cmd = mgmt_pending_find(opcode, hdev->id);
Johan Hedberga5c29682011-02-19 12:05:57 -03002251 if (!cmd)
2252 return -ENOENT;
2253
Johan Hedberga5c29682011-02-19 12:05:57 -03002254 bacpy(&rp.bdaddr, bdaddr);
2255 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002256 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002257
Johan Hedberga664b5b2011-02-19 12:06:02 -03002258 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002259
2260 return err;
2261}
2262
Johan Hedberg744cf192011-11-08 20:40:14 +02002263int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2264 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002265{
Johan Hedberg744cf192011-11-08 20:40:14 +02002266 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002267 MGMT_OP_USER_CONFIRM_REPLY);
2268}
2269
Johan Hedberg744cf192011-11-08 20:40:14 +02002270int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2271 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002272{
Johan Hedberg744cf192011-11-08 20:40:14 +02002273 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002274 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2275}
Johan Hedberg2a611692011-02-19 12:06:00 -03002276
Johan Hedberg744cf192011-11-08 20:40:14 +02002277int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002278{
2279 struct mgmt_ev_auth_failed ev;
2280
Johan Hedberg2a611692011-02-19 12:06:00 -03002281 bacpy(&ev.bdaddr, bdaddr);
2282 ev.status = status;
2283
Johan Hedberg744cf192011-11-08 20:40:14 +02002284 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002285}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002286
Johan Hedberg744cf192011-11-08 20:40:14 +02002287int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002288{
2289 struct pending_cmd *cmd;
2290 struct mgmt_cp_set_local_name ev;
2291 int err;
2292
2293 memset(&ev, 0, sizeof(ev));
2294 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2295
Johan Hedberg744cf192011-11-08 20:40:14 +02002296 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev->id);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002297 if (!cmd)
2298 goto send_event;
2299
2300 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002301 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2302 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002303 goto failed;
2304 }
2305
Johan Hedberg744cf192011-11-08 20:40:14 +02002306 hci_dev_lock_bh(hdev);
2307 update_eir(hdev);
2308 hci_dev_unlock_bh(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002309
Johan Hedberg744cf192011-11-08 20:40:14 +02002310 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002311 sizeof(ev));
2312 if (err < 0)
2313 goto failed;
2314
2315send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002316 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002317 cmd ? cmd->sk : NULL);
2318
2319failed:
2320 if (cmd)
2321 mgmt_pending_remove(cmd);
2322 return err;
2323}
Szymon Jancc35938b2011-03-22 13:12:21 +01002324
Johan Hedberg744cf192011-11-08 20:40:14 +02002325int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2326 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002327{
2328 struct pending_cmd *cmd;
2329 int err;
2330
Johan Hedberg744cf192011-11-08 20:40:14 +02002331 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002332
Johan Hedberg744cf192011-11-08 20:40:14 +02002333 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev->id);
Szymon Jancc35938b2011-03-22 13:12:21 +01002334 if (!cmd)
2335 return -ENOENT;
2336
2337 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002338 err = cmd_status(cmd->sk, hdev->id,
2339 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002340 } else {
2341 struct mgmt_rp_read_local_oob_data rp;
2342
2343 memcpy(rp.hash, hash, sizeof(rp.hash));
2344 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2345
Johan Hedberg744cf192011-11-08 20:40:14 +02002346 err = cmd_complete(cmd->sk, hdev->id,
2347 MGMT_OP_READ_LOCAL_OOB_DATA,
2348 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002349 }
2350
2351 mgmt_pending_remove(cmd);
2352
2353 return err;
2354}
Johan Hedberge17acd42011-03-30 23:57:16 +03002355
Johan Hedberg744cf192011-11-08 20:40:14 +02002356int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2357 u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002358{
2359 struct mgmt_ev_device_found ev;
2360
2361 memset(&ev, 0, sizeof(ev));
2362
Johan Hedberg4c659c32011-11-07 23:13:39 +02002363 bacpy(&ev.addr.bdaddr, bdaddr);
2364 ev.addr.type = link_to_mgmt(type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002365 ev.rssi = rssi;
2366
2367 if (eir)
2368 memcpy(ev.eir, eir, sizeof(ev.eir));
2369
Andre Guedesf8523592011-09-09 18:56:26 -03002370 if (dev_class)
2371 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2372
Johan Hedberg744cf192011-11-08 20:40:14 +02002373 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002374}
Johan Hedberga88a9652011-03-30 13:18:12 +03002375
Johan Hedberg744cf192011-11-08 20:40:14 +02002376int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002377{
2378 struct mgmt_ev_remote_name ev;
2379
2380 memset(&ev, 0, sizeof(ev));
2381
2382 bacpy(&ev.bdaddr, bdaddr);
2383 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2384
Johan Hedberg744cf192011-11-08 20:40:14 +02002385 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002386}
Johan Hedberg314b2382011-04-27 10:29:57 -04002387
Johan Hedberg744cf192011-11-08 20:40:14 +02002388int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002389{
2390 struct pending_cmd *cmd;
2391 int err;
2392
Johan Hedberg744cf192011-11-08 20:40:14 +02002393 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev->id);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002394 if (!cmd)
2395 return -ENOENT;
2396
Johan Hedberg744cf192011-11-08 20:40:14 +02002397 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002398 mgmt_pending_remove(cmd);
2399
2400 return err;
2401}
2402
Johan Hedberg744cf192011-11-08 20:40:14 +02002403int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002404{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002405 struct pending_cmd *cmd;
2406
2407 if (discovering)
Johan Hedberg744cf192011-11-08 20:40:14 +02002408 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev->id);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002409 else
Johan Hedberg744cf192011-11-08 20:40:14 +02002410 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002411
2412 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002413 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002414 mgmt_pending_remove(cmd);
2415 }
2416
Johan Hedberg744cf192011-11-08 20:40:14 +02002417 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002418 sizeof(discovering), NULL);
2419}
Antti Julku5e762442011-08-25 16:48:02 +03002420
Johan Hedberg744cf192011-11-08 20:40:14 +02002421int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002422{
2423 struct pending_cmd *cmd;
2424 struct mgmt_ev_device_blocked ev;
2425
Johan Hedberg744cf192011-11-08 20:40:14 +02002426 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev->id);
Antti Julku5e762442011-08-25 16:48:02 +03002427
2428 bacpy(&ev.bdaddr, bdaddr);
2429
Johan Hedberg744cf192011-11-08 20:40:14 +02002430 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2431 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002432}
2433
Johan Hedberg744cf192011-11-08 20:40:14 +02002434int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002435{
2436 struct pending_cmd *cmd;
2437 struct mgmt_ev_device_unblocked ev;
2438
Johan Hedberg744cf192011-11-08 20:40:14 +02002439 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev->id);
Antti Julku5e762442011-08-25 16:48:02 +03002440
2441 bacpy(&ev.bdaddr, bdaddr);
2442
Johan Hedberg744cf192011-11-08 20:40:14 +02002443 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2444 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002445}