blob: 4cb2f958fb1076b5b1b6a13c60549e4507257408 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
39 __u16 opcode;
40 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
Johannes Bergb5ad8b72011-06-01 08:54:45 +020046static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047
Szymon Janc4e51eae2011-02-25 19:05:48 +010048static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020049{
50 struct sk_buff *skb;
51 struct mgmt_hdr *hdr;
52 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030053 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +020054
Szymon Janc34eb5252011-02-28 14:10:08 +010055 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020056
57 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
58 if (!skb)
59 return -ENOMEM;
60
61 hdr = (void *) skb_put(skb, sizeof(*hdr));
62
63 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010064 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020065 hdr->len = cpu_to_le16(sizeof(*ev));
66
67 ev = (void *) skb_put(skb, sizeof(*ev));
68 ev->status = status;
69 put_unaligned_le16(cmd, &ev->opcode);
70
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030071 err = sock_queue_rcv_skb(sk, skb);
72 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020073 kfree_skb(skb);
74
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030075 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +020076}
77
Szymon Janc4e51eae2011-02-25 19:05:48 +010078static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
79 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020080{
81 struct sk_buff *skb;
82 struct mgmt_hdr *hdr;
83 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030084 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020085
86 BT_DBG("sock %p", sk);
87
Johan Hedberga38528f2011-01-22 06:46:43 +020088 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020089 if (!skb)
90 return -ENOMEM;
91
92 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020093
Johan Hedberg02d98122010-12-13 21:07:04 +020094 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010095 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020096 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020097
Johan Hedberga38528f2011-01-22 06:46:43 +020098 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
99 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100100
101 if (rp)
102 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200103
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300104 err = sock_queue_rcv_skb(sk, skb);
105 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 kfree_skb(skb);
107
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300108 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200109}
110
Johan Hedberga38528f2011-01-22 06:46:43 +0200111static int read_version(struct sock *sk)
112{
113 struct mgmt_rp_read_version rp;
114
115 BT_DBG("sock %p", sk);
116
117 rp.version = MGMT_VERSION;
118 put_unaligned_le16(MGMT_REVISION, &rp.revision);
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
121 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200122}
123
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124static int read_index_list(struct sock *sk)
125{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126 struct mgmt_rp_read_index_list *rp;
127 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200128 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200131 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132
133 BT_DBG("sock %p", sk);
134
135 read_lock(&hci_dev_list_lock);
136
137 count = 0;
138 list_for_each(p, &hci_dev_list) {
139 count++;
140 }
141
Johan Hedberga38528f2011-01-22 06:46:43 +0200142 rp_len = sizeof(*rp) + (2 * count);
143 rp = kmalloc(rp_len, GFP_ATOMIC);
144 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100147 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(count, &rp->num_controllers);
150
151 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200152 list_for_each_entry(d, &hci_dev_list, list) {
Johan 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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200204 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200217 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200218
Szymon Janc4e51eae2011-02-25 19:05:48 +0100219 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200220}
221
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200222static void mgmt_pending_free(struct pending_cmd *cmd)
223{
224 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100225 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200226 kfree(cmd);
227}
228
Johan Hedberg366a0332011-02-19 12:05:55 -0300229static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
230 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200231{
232 struct pending_cmd *cmd;
233
234 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
235 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300236 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200237
238 cmd->opcode = opcode;
239 cmd->index = index;
240
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100241 cmd->param = kmalloc(len, GFP_ATOMIC);
242 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200243 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300244 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200245 }
246
Szymon Janc8fce6352011-03-22 13:12:20 +0100247 if (data)
248 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200249
250 cmd->sk = sk;
251 sock_hold(sk);
252
253 list_add(&cmd->list, &cmd_list);
254
Johan Hedberg366a0332011-02-19 12:05:55 -0300255 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200256}
257
258static void mgmt_pending_foreach(u16 opcode, int index,
259 void (*cb)(struct pending_cmd *cmd, void *data),
260 void *data)
261{
262 struct list_head *p, *n;
263
264 list_for_each_safe(p, n, &cmd_list) {
265 struct pending_cmd *cmd;
266
267 cmd = list_entry(p, struct pending_cmd, list);
268
Johan Hedbergb24752f2011-11-03 14:40:33 +0200269 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200270 continue;
271
272 if (index >= 0 && cmd->index != index)
273 continue;
274
275 cb(cmd, data);
276 }
277}
278
279static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
280{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200281 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200283 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200284 if (cmd->opcode != opcode)
285 continue;
286
287 if (index >= 0 && cmd->index != index)
288 continue;
289
290 return cmd;
291 }
292
293 return NULL;
294}
295
Johan Hedberga664b5b2011-02-19 12:06:02 -0300296static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200298 list_del(&cmd->list);
299 mgmt_pending_free(cmd);
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200304 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300307 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
309 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Janc4e51eae2011-02-25 19:05:48 +0100311 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100313 if (len != sizeof(*cp))
314 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
315
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100318 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
Andre Guedes8c156c32011-07-07 10:30:36 -0300320 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321
322 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200323 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100324 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200325 goto failed;
326 }
327
Szymon Janc4e51eae2011-02-25 19:05:48 +0100328 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
329 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330 goto failed;
331 }
332
Szymon Janc4e51eae2011-02-25 19:05:48 +0100333 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 if (!cmd) {
335 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300337 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338
Johan Hedberg72a734e2010-12-30 00:38:22 +0200339 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340 queue_work(hdev->workqueue, &hdev->power_on);
341 else
Johan Hedberg32435532011-11-07 22:16:04 +0200342 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
Johan Hedberg366a0332011-02-19 12:05:55 -0300344 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345
346failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300347 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300349 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350}
351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
353 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200355 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 u8 scan;
359 int err;
360
361 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Janc4e51eae2011-02-25 19:05:48 +0100363 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100365 if (len != sizeof(*cp))
366 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
367
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100370 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
Andre Guedes8c156c32011-07-07 10:30:36 -0300372 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373
374 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100375 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 goto failed;
377 }
378
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
380 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
381 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 goto failed;
383 }
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100387 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388 goto failed;
389 }
390
Szymon Janc4e51eae2011-02-25 19:05:48 +0100391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300392 if (!cmd) {
393 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396
397 scan = SCAN_PAGE;
398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200401 else
402 cancel_delayed_work_sync(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
404 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
405 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300406 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200407
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200408 if (cp->val)
409 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
410
Johan Hedberg73f22f62010-12-29 16:00:25 +0200411failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300412 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200413 hci_dev_put(hdev);
414
415 return err;
416}
417
Szymon Janc4e51eae2011-02-25 19:05:48 +0100418static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
419 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200420{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200421 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300423 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424 u8 scan;
425 int err;
426
427 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100431 if (len != sizeof(*cp))
432 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
433
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100436 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437
Andre Guedes8c156c32011-07-07 10:30:36 -0300438 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439
440 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
446 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
447 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448 goto failed;
449 }
450
Johan Hedberg72a734e2010-12-30 00:38:22 +0200451 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100452 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453 goto failed;
454 }
455
Szymon Janc4e51eae2011-02-25 19:05:48 +0100456 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300457 if (!cmd) {
458 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300460 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
Johan Hedberg72a734e2010-12-30 00:38:22 +0200462 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463 scan = SCAN_PAGE;
464 else
465 scan = 0;
466
467 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
468 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300469 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200470
471failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300472 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200473 hci_dev_put(hdev);
474
475 return err;
476}
477
Szymon Janc4e51eae2011-02-25 19:05:48 +0100478static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
479 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200480{
481 struct sk_buff *skb;
482 struct mgmt_hdr *hdr;
483
484 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
485 if (!skb)
486 return -ENOMEM;
487
488 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
489
490 hdr = (void *) skb_put(skb, sizeof(*hdr));
491 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100492 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200493 hdr->len = cpu_to_le16(data_len);
494
Szymon Janc4e51eae2011-02-25 19:05:48 +0100495 if (data)
496 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200497
498 hci_send_to_sock(NULL, skb, skip_sk);
499 kfree_skb(skb);
500
501 return 0;
502}
503
Johan Hedberg053f0212011-01-26 13:07:10 +0200504static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
505{
Johan Hedberga38528f2011-01-22 06:46:43 +0200506 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200507
Johan Hedberga38528f2011-01-22 06:46:43 +0200508 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200509
Szymon Janc4e51eae2011-02-25 19:05:48 +0100510 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200511}
512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
514 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200515{
516 struct mgmt_mode *cp, ev;
517 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200518 int err;
519
520 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100524 if (len != sizeof(*cp))
525 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
526
Szymon Janc4e51eae2011-02-25 19:05:48 +0100527 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100529 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530
Andre Guedes8c156c32011-07-07 10:30:36 -0300531 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532
533 if (cp->val)
534 set_bit(HCI_PAIRABLE, &hdev->flags);
535 else
536 clear_bit(HCI_PAIRABLE, &hdev->flags);
537
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539 if (err < 0)
540 goto failed;
541
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 ev.val = cp->val;
543
Szymon Janc4e51eae2011-02-25 19:05:48 +0100544 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200545
546failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300547 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200548 hci_dev_put(hdev);
549
550 return err;
551}
552
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300553#define EIR_FLAGS 0x01 /* flags */
554#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
555#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
556#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
557#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
558#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
559#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
560#define EIR_NAME_SHORT 0x08 /* shortened local name */
561#define EIR_NAME_COMPLETE 0x09 /* complete local name */
562#define EIR_TX_POWER 0x0A /* transmit power level */
563#define EIR_DEVICE_ID 0x10 /* device ID */
564
565#define PNP_INFO_SVCLASS_ID 0x1200
566
567static u8 bluetooth_base_uuid[] = {
568 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
569 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570};
571
572static u16 get_uuid16(u8 *uuid128)
573{
574 u32 val;
575 int i;
576
577 for (i = 0; i < 12; i++) {
578 if (bluetooth_base_uuid[i] != uuid128[i])
579 return 0;
580 }
581
582 memcpy(&val, &uuid128[12], 4);
583
584 val = le32_to_cpu(val);
585 if (val > 0xffff)
586 return 0;
587
588 return (u16) val;
589}
590
591static void create_eir(struct hci_dev *hdev, u8 *data)
592{
593 u8 *ptr = data;
594 u16 eir_len = 0;
595 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
596 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200597 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598 size_t name_len;
599
600 name_len = strlen(hdev->dev_name);
601
602 if (name_len > 0) {
603 /* EIR Data type */
604 if (name_len > 48) {
605 name_len = 48;
606 ptr[1] = EIR_NAME_SHORT;
607 } else
608 ptr[1] = EIR_NAME_COMPLETE;
609
610 /* EIR Data length */
611 ptr[0] = name_len + 1;
612
613 memcpy(ptr + 2, hdev->dev_name, name_len);
614
615 eir_len += (name_len + 2);
616 ptr += (name_len + 2);
617 }
618
619 memset(uuid16_list, 0, sizeof(uuid16_list));
620
621 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200622 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300623 u16 uuid16;
624
625 uuid16 = get_uuid16(uuid->uuid);
626 if (uuid16 == 0)
627 return;
628
629 if (uuid16 < 0x1100)
630 continue;
631
632 if (uuid16 == PNP_INFO_SVCLASS_ID)
633 continue;
634
635 /* Stop if not enough space to put next UUID */
636 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
637 truncated = 1;
638 break;
639 }
640
641 /* Check for duplicates */
642 for (i = 0; uuid16_list[i] != 0; i++)
643 if (uuid16_list[i] == uuid16)
644 break;
645
646 if (uuid16_list[i] == 0) {
647 uuid16_list[i] = uuid16;
648 eir_len += sizeof(u16);
649 }
650 }
651
652 if (uuid16_list[0] != 0) {
653 u8 *length = ptr;
654
655 /* EIR Data type */
656 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
657
658 ptr += 2;
659 eir_len += 2;
660
661 for (i = 0; uuid16_list[i] != 0; i++) {
662 *ptr++ = (uuid16_list[i] & 0x00ff);
663 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
664 }
665
666 /* EIR Data length */
667 *length = (i * sizeof(u16)) + 1;
668 }
669}
670
671static int update_eir(struct hci_dev *hdev)
672{
673 struct hci_cp_write_eir cp;
674
675 if (!(hdev->features[6] & LMP_EXT_INQ))
676 return 0;
677
678 if (hdev->ssp_mode == 0)
679 return 0;
680
681 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
682 return 0;
683
684 memset(&cp, 0, sizeof(cp));
685
686 create_eir(hdev, cp.data);
687
688 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
689 return 0;
690
691 memcpy(hdev->eir, cp.data, sizeof(cp.data));
692
693 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
694}
695
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696static u8 get_service_classes(struct hci_dev *hdev)
697{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300698 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699 u8 val = 0;
700
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300701 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200703
704 return val;
705}
706
707static int update_class(struct hci_dev *hdev)
708{
709 u8 cod[3];
710
711 BT_DBG("%s", hdev->name);
712
713 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
714 return 0;
715
716 cod[0] = hdev->minor_class;
717 cod[1] = hdev->major_class;
718 cod[2] = get_service_classes(hdev);
719
720 if (memcmp(cod, hdev->dev_class, 3) == 0)
721 return 0;
722
723 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
724}
725
Szymon Janc4e51eae2011-02-25 19:05:48 +0100726static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200727{
728 struct mgmt_cp_add_uuid *cp;
729 struct hci_dev *hdev;
730 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200731 int err;
732
733 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Szymon Janc4e51eae2011-02-25 19:05:48 +0100735 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100737 if (len != sizeof(*cp))
738 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
739
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743
Andre Guedes8c156c32011-07-07 10:30:36 -0300744 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200745
746 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
747 if (!uuid) {
748 err = -ENOMEM;
749 goto failed;
750 }
751
752 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200753 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200754
755 list_add(&uuid->list, &hdev->uuids);
756
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200757 err = update_class(hdev);
758 if (err < 0)
759 goto failed;
760
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300761 err = update_eir(hdev);
762 if (err < 0)
763 goto failed;
764
Szymon Janc4e51eae2011-02-25 19:05:48 +0100765 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200766
767failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300768 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769 hci_dev_put(hdev);
770
771 return err;
772}
773
Szymon Janc4e51eae2011-02-25 19:05:48 +0100774static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200775{
776 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100777 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778 struct hci_dev *hdev;
779 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200780 int err, found;
781
782 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Szymon Janc4e51eae2011-02-25 19:05:48 +0100784 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100786 if (len != sizeof(*cp))
787 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
788
Szymon Janc4e51eae2011-02-25 19:05:48 +0100789 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100791 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792
Andre Guedes8c156c32011-07-07 10:30:36 -0300793 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
795 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
796 err = hci_uuids_clear(hdev);
797 goto unlock;
798 }
799
800 found = 0;
801
802 list_for_each_safe(p, n, &hdev->uuids) {
803 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
804
805 if (memcmp(match->uuid, cp->uuid, 16) != 0)
806 continue;
807
808 list_del(&match->list);
809 found++;
810 }
811
812 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100813 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200814 goto unlock;
815 }
816
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200817 err = update_class(hdev);
818 if (err < 0)
819 goto unlock;
820
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300821 err = update_eir(hdev);
822 if (err < 0)
823 goto unlock;
824
Szymon Janc4e51eae2011-02-25 19:05:48 +0100825 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200826
827unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300828 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200829 hci_dev_put(hdev);
830
831 return err;
832}
833
Szymon Janc4e51eae2011-02-25 19:05:48 +0100834static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
835 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200836{
837 struct hci_dev *hdev;
838 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200839 int err;
840
841 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Szymon Janc4e51eae2011-02-25 19:05:48 +0100843 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100845 if (len != sizeof(*cp))
846 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
847
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851
Andre Guedes8c156c32011-07-07 10:30:36 -0300852 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200853
854 hdev->major_class = cp->major;
855 hdev->minor_class = cp->minor;
856
857 err = update_class(hdev);
858
859 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100860 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861
Andre Guedes8c156c32011-07-07 10:30:36 -0300862 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200863 hci_dev_put(hdev);
864
865 return err;
866}
867
Szymon Janc4e51eae2011-02-25 19:05:48 +0100868static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
869 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870{
871 struct hci_dev *hdev;
872 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873 int err;
874
875 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100877 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100878 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100879
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
Andre Guedes8c156c32011-07-07 10:30:36 -0300884 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887
888 if (cp->enable) {
889 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
890 err = 0;
891 } else {
892 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
893 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300894 if (err == 0)
895 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200896 }
897
898 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100899 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
900 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300901 else
902 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
903
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904
Andre Guedes8c156c32011-07-07 10:30:36 -0300905 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906 hci_dev_put(hdev);
907
908 return err;
909}
910
Johan Hedberg86742e12011-11-07 23:13:38 +0200911static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
912 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200913{
914 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200915 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300917 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200918
919 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100920
921 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200922 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100923
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200924 key_count = get_unaligned_le16(&cp->key_count);
925
Johan Hedberg86742e12011-11-07 23:13:38 +0200926 expected_len = sizeof(*cp) + key_count *
927 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300928 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200929 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300930 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200931 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200932 }
933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200936 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200937
Szymon Janc4e51eae2011-02-25 19:05:48 +0100938 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200939 key_count);
940
Andre Guedes8c156c32011-07-07 10:30:36 -0300941 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200942
943 hci_link_keys_clear(hdev);
944
945 set_bit(HCI_LINK_KEYS, &hdev->flags);
946
947 if (cp->debug_keys)
948 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
949 else
950 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
951
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300952 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200953 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700955 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200956 key->pin_len);
957 }
958
Andre Guedes8c156c32011-07-07 10:30:36 -0300959 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200960 hci_dev_put(hdev);
961
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300962 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200963}
964
Johan Hedberg86742e12011-11-07 23:13:38 +0200965static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
966 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967{
968 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200969 struct mgmt_cp_remove_keys *cp;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200970 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200971 int err;
972
973 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100975 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200976 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100977
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200979 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200980 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200981
Andre Guedes8c156c32011-07-07 10:30:36 -0300982 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200983
984 err = hci_remove_link_key(hdev, &cp->bdaddr);
985 if (err < 0) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200986 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200987 goto unlock;
988 }
989
990 err = 0;
991
992 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
993 goto unlock;
994
995 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
996 if (conn) {
997 struct hci_cp_disconnect dc;
998
999 put_unaligned_le16(conn->handle, &dc.handle);
1000 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -04001001 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001002 }
1003
1004unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001005 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Szymon Janc4e51eae2011-02-25 19:05:48 +01001011static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001012{
1013 struct hci_dev *hdev;
1014 struct mgmt_cp_disconnect *cp;
1015 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001016 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001017 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001018 int err;
1019
1020 BT_DBG("");
1021
1022 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001024 if (len != sizeof(*cp))
1025 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1026
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001030
Andre Guedes8c156c32011-07-07 10:30:36 -03001031 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032
1033 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001035 goto failed;
1036 }
1037
Szymon Janc4e51eae2011-02-25 19:05:48 +01001038 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1039 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001040 goto failed;
1041 }
1042
1043 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001044 if (!conn)
1045 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1046
Johan Hedberg8962ee72011-01-20 12:40:27 +02001047 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001048 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 goto failed;
1050 }
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001053 if (!cmd) {
1054 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001055 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001056 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057
1058 put_unaligned_le16(conn->handle, &dc.handle);
1059 dc.reason = 0x13; /* Remote User Terminated Connection */
1060
1061 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1062 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001063 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064
1065failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001066 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001067 hci_dev_put(hdev);
1068
1069 return err;
1070}
1071
Johan Hedberg4c659c32011-11-07 23:13:39 +02001072static u8 link_to_mgmt(u8 link_type)
1073{
1074 switch (link_type) {
1075 case LE_LINK:
1076 return MGMT_ADDR_LE;
1077 case ACL_LINK:
1078 return MGMT_ADDR_BREDR;
1079 default:
1080 return MGMT_ADDR_INVALID;
1081 }
1082}
1083
Szymon Janc8ce62842011-03-01 16:55:32 +01001084static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001085{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001086 struct mgmt_rp_get_connections *rp;
1087 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001088 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001089 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001090 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001091 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001092 int i, err;
1093
1094 BT_DBG("");
1095
Szymon Janc4e51eae2011-02-25 19:05:48 +01001096 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001098 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099
Andre Guedes8c156c32011-07-07 10:30:36 -03001100 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001101
1102 count = 0;
1103 list_for_each(p, &hdev->conn_hash.list) {
1104 count++;
1105 }
1106
Johan Hedberg4c659c32011-11-07 23:13:39 +02001107 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001108 rp = kmalloc(rp_len, GFP_ATOMIC);
1109 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001110 err = -ENOMEM;
1111 goto unlock;
1112 }
1113
Johan Hedberg2784eb42011-01-21 13:56:35 +02001114 put_unaligned_le16(count, &rp->conn_count);
1115
Johan Hedberg2784eb42011-01-21 13:56:35 +02001116 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001117 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1118 bacpy(&rp->addr[i].bdaddr, &c->dst);
1119 rp->addr[i].type = link_to_mgmt(c->type);
1120 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1121 continue;
1122 i++;
1123 }
1124
1125 /* Recalculate length in case of filtered SCO connections, etc */
1126 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001127
Szymon Janc4e51eae2011-02-25 19:05:48 +01001128 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001129
1130unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001131 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001132 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001133 hci_dev_put(hdev);
1134 return err;
1135}
1136
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001137static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1138 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1139{
1140 struct pending_cmd *cmd;
1141 int err;
1142
1143 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1144 sizeof(*cp));
1145 if (!cmd)
1146 return -ENOMEM;
1147
1148 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1149 &cp->bdaddr);
1150 if (err < 0)
1151 mgmt_pending_remove(cmd);
1152
1153 return err;
1154}
1155
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1157 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001158{
1159 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001160 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001161 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001162 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001163 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001164 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001165 int err;
1166
1167 BT_DBG("");
1168
1169 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001170
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001171 if (len != sizeof(*cp))
1172 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1173
Szymon Janc4e51eae2011-02-25 19:05:48 +01001174 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001175 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001176 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177
Andre Guedes8c156c32011-07-07 10:30:36 -03001178 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179
1180 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 goto failed;
1183 }
1184
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001185 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1186 if (!conn) {
1187 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1188 goto failed;
1189 }
1190
1191 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1192 bacpy(&ncp.bdaddr, &cp->bdaddr);
1193
1194 BT_ERR("PIN code is not 16 bytes long");
1195
1196 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1197 if (err >= 0)
1198 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1199 EINVAL);
1200
1201 goto failed;
1202 }
1203
Szymon Janc4e51eae2011-02-25 19:05:48 +01001204 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001205 if (!cmd) {
1206 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001207 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001208 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001209
1210 bacpy(&reply.bdaddr, &cp->bdaddr);
1211 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001212 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001213
1214 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1215 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001216 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001217
1218failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001219 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001220 hci_dev_put(hdev);
1221
1222 return err;
1223}
1224
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1226 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001227{
1228 struct hci_dev *hdev;
1229 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 int err;
1231
1232 BT_DBG("");
1233
1234 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001235
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001236 if (len != sizeof(*cp))
1237 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1238 EINVAL);
1239
Szymon Janc4e51eae2011-02-25 19:05:48 +01001240 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001241 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1243 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001244
Andre Guedes8c156c32011-07-07 10:30:36 -03001245 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001246
1247 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001248 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1249 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001250 goto failed;
1251 }
1252
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001253 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001254
1255failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001256 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001257 hci_dev_put(hdev);
1258
1259 return err;
1260}
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1263 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001264{
1265 struct hci_dev *hdev;
1266 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001267
1268 BT_DBG("");
1269
1270 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001271
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001272 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001273 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001274
Szymon Janc4e51eae2011-02-25 19:05:48 +01001275 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001276 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001277 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001278
Andre Guedes8c156c32011-07-07 10:30:36 -03001279 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001280
1281 hdev->io_capability = cp->io_capability;
1282
1283 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001284 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001285
Andre Guedes8c156c32011-07-07 10:30:36 -03001286 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001287 hci_dev_put(hdev);
1288
Szymon Janc4e51eae2011-02-25 19:05:48 +01001289 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001290}
1291
Johan Hedberge9a416b2011-02-19 12:05:56 -03001292static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1293{
1294 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001295 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001296
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001297 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001298 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1299 continue;
1300
1301 if (cmd->index != hdev->id)
1302 continue;
1303
1304 if (cmd->user_data != conn)
1305 continue;
1306
1307 return cmd;
1308 }
1309
1310 return NULL;
1311}
1312
1313static void pairing_complete(struct pending_cmd *cmd, u8 status)
1314{
1315 struct mgmt_rp_pair_device rp;
1316 struct hci_conn *conn = cmd->user_data;
1317
Johan Hedberge9a416b2011-02-19 12:05:56 -03001318 bacpy(&rp.bdaddr, &conn->dst);
1319 rp.status = status;
1320
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322
1323 /* So we don't get further callbacks for this connection */
1324 conn->connect_cfm_cb = NULL;
1325 conn->security_cfm_cb = NULL;
1326 conn->disconn_cfm_cb = NULL;
1327
1328 hci_conn_put(conn);
1329
Johan Hedberga664b5b2011-02-19 12:06:02 -03001330 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331}
1332
1333static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1334{
1335 struct pending_cmd *cmd;
1336
1337 BT_DBG("status %u", status);
1338
1339 cmd = find_pairing(conn);
1340 if (!cmd) {
1341 BT_DBG("Unable to find a pending command");
1342 return;
1343 }
1344
1345 pairing_complete(cmd, status);
1346}
1347
Szymon Janc4e51eae2011-02-25 19:05:48 +01001348static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349{
1350 struct hci_dev *hdev;
1351 struct mgmt_cp_pair_device *cp;
1352 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001353 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001354 u8 sec_level, auth_type;
1355 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001356 int err;
1357
1358 BT_DBG("");
1359
1360 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001361
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001362 if (len != sizeof(*cp))
1363 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1364
Szymon Janc4e51eae2011-02-25 19:05:48 +01001365 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001366 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001368
Andre Guedes8c156c32011-07-07 10:30:36 -03001369 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001371 sec_level = BT_SECURITY_MEDIUM;
1372 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001374 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001376
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001377 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1378 if (entry)
1379 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1380 auth_type);
1381 else
1382 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1383 auth_type);
1384
Ville Tervo30e76272011-02-22 16:10:53 -03001385 if (IS_ERR(conn)) {
1386 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001387 goto unlock;
1388 }
1389
1390 if (conn->connect_cfm_cb) {
1391 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001392 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001393 goto unlock;
1394 }
1395
Szymon Janc4e51eae2011-02-25 19:05:48 +01001396 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001397 if (!cmd) {
1398 err = -ENOMEM;
1399 hci_conn_put(conn);
1400 goto unlock;
1401 }
1402
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001403 /* For LE, just connecting isn't a proof that the pairing finished */
1404 if (!entry)
1405 conn->connect_cfm_cb = pairing_complete_cb;
1406
Johan Hedberge9a416b2011-02-19 12:05:56 -03001407 conn->security_cfm_cb = pairing_complete_cb;
1408 conn->disconn_cfm_cb = pairing_complete_cb;
1409 conn->io_capability = cp->io_cap;
1410 cmd->user_data = conn;
1411
1412 if (conn->state == BT_CONNECTED &&
1413 hci_conn_security(conn, sec_level, auth_type))
1414 pairing_complete(cmd, 0);
1415
1416 err = 0;
1417
1418unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001419 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001420 hci_dev_put(hdev);
1421
1422 return err;
1423}
1424
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1426 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001427{
1428 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001430 struct pending_cmd *cmd;
1431 struct hci_dev *hdev;
1432 int err;
1433
1434 BT_DBG("");
1435
Johan Hedberga5c29682011-02-19 12:05:57 -03001436 if (success) {
1437 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1438 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1439 } else {
1440 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1441 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1442 }
1443
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001444 if (len != sizeof(*cp))
1445 return cmd_status(sk, index, mgmt_op, EINVAL);
1446
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001448 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001450
Andre Guedes8c156c32011-07-07 10:30:36 -03001451 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001452
Johan Hedberga5c29682011-02-19 12:05:57 -03001453 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001454 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001455 goto failed;
1456 }
1457
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001459 if (!cmd) {
1460 err = -ENOMEM;
1461 goto failed;
1462 }
1463
1464 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001465 if (err < 0)
1466 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001467
1468failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001469 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001470 hci_dev_put(hdev);
1471
1472 return err;
1473}
1474
Johan Hedbergb312b1612011-03-16 14:29:37 +02001475static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1476 u16 len)
1477{
1478 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1479 struct hci_cp_write_local_name hci_cp;
1480 struct hci_dev *hdev;
1481 struct pending_cmd *cmd;
1482 int err;
1483
1484 BT_DBG("");
1485
1486 if (len != sizeof(*mgmt_cp))
1487 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1488
1489 hdev = hci_dev_get(index);
1490 if (!hdev)
1491 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1492
Andre Guedes8c156c32011-07-07 10:30:36 -03001493 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001494
1495 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1496 if (!cmd) {
1497 err = -ENOMEM;
1498 goto failed;
1499 }
1500
1501 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1502 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1503 &hci_cp);
1504 if (err < 0)
1505 mgmt_pending_remove(cmd);
1506
1507failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001508 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001509 hci_dev_put(hdev);
1510
1511 return err;
1512}
1513
Szymon Jancc35938b2011-03-22 13:12:21 +01001514static int read_local_oob_data(struct sock *sk, u16 index)
1515{
1516 struct hci_dev *hdev;
1517 struct pending_cmd *cmd;
1518 int err;
1519
1520 BT_DBG("hci%u", index);
1521
1522 hdev = hci_dev_get(index);
1523 if (!hdev)
1524 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1525 ENODEV);
1526
Andre Guedes8c156c32011-07-07 10:30:36 -03001527 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001528
1529 if (!test_bit(HCI_UP, &hdev->flags)) {
1530 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1531 ENETDOWN);
1532 goto unlock;
1533 }
1534
1535 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1536 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1537 EOPNOTSUPP);
1538 goto unlock;
1539 }
1540
1541 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1542 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1543 goto unlock;
1544 }
1545
1546 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1547 if (!cmd) {
1548 err = -ENOMEM;
1549 goto unlock;
1550 }
1551
1552 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1553 if (err < 0)
1554 mgmt_pending_remove(cmd);
1555
1556unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001557 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001558 hci_dev_put(hdev);
1559
1560 return err;
1561}
1562
Szymon Janc2763eda2011-03-22 13:12:22 +01001563static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1564 u16 len)
1565{
1566 struct hci_dev *hdev;
1567 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1568 int err;
1569
1570 BT_DBG("hci%u ", index);
1571
1572 if (len != sizeof(*cp))
1573 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1574 EINVAL);
1575
1576 hdev = hci_dev_get(index);
1577 if (!hdev)
1578 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1579 ENODEV);
1580
Andre Guedes8c156c32011-07-07 10:30:36 -03001581 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001582
1583 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1584 cp->randomizer);
1585 if (err < 0)
1586 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1587 else
1588 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1589 0);
1590
Andre Guedes8c156c32011-07-07 10:30:36 -03001591 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001592 hci_dev_put(hdev);
1593
1594 return err;
1595}
1596
1597static int remove_remote_oob_data(struct sock *sk, u16 index,
1598 unsigned char *data, u16 len)
1599{
1600 struct hci_dev *hdev;
1601 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1602 int err;
1603
1604 BT_DBG("hci%u ", index);
1605
1606 if (len != sizeof(*cp))
1607 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1608 EINVAL);
1609
1610 hdev = hci_dev_get(index);
1611 if (!hdev)
1612 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1613 ENODEV);
1614
Andre Guedes8c156c32011-07-07 10:30:36 -03001615 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001616
1617 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1618 if (err < 0)
1619 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1620 -err);
1621 else
1622 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1623 NULL, 0);
1624
Andre Guedes8c156c32011-07-07 10:30:36 -03001625 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001626 hci_dev_put(hdev);
1627
1628 return err;
1629}
1630
Johan Hedberg14a53662011-04-27 10:29:56 -04001631static int start_discovery(struct sock *sk, u16 index)
1632{
Johan Hedberg14a53662011-04-27 10:29:56 -04001633 struct pending_cmd *cmd;
1634 struct hci_dev *hdev;
1635 int err;
1636
1637 BT_DBG("hci%u", index);
1638
1639 hdev = hci_dev_get(index);
1640 if (!hdev)
1641 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1642
1643 hci_dev_lock_bh(hdev);
1644
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001645 if (!test_bit(HCI_UP, &hdev->flags)) {
1646 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1647 goto failed;
1648 }
1649
Johan Hedberg14a53662011-04-27 10:29:56 -04001650 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1651 if (!cmd) {
1652 err = -ENOMEM;
1653 goto failed;
1654 }
1655
Andre Guedes2519a1f2011-11-07 11:45:24 -03001656 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001657 if (err < 0)
1658 mgmt_pending_remove(cmd);
1659
1660failed:
1661 hci_dev_unlock_bh(hdev);
1662 hci_dev_put(hdev);
1663
1664 return err;
1665}
1666
1667static int stop_discovery(struct sock *sk, u16 index)
1668{
1669 struct hci_dev *hdev;
1670 struct pending_cmd *cmd;
1671 int err;
1672
1673 BT_DBG("hci%u", index);
1674
1675 hdev = hci_dev_get(index);
1676 if (!hdev)
1677 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1678
1679 hci_dev_lock_bh(hdev);
1680
1681 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1682 if (!cmd) {
1683 err = -ENOMEM;
1684 goto failed;
1685 }
1686
Andre Guedes023d50492011-11-04 14:16:52 -03001687 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001688 if (err < 0)
1689 mgmt_pending_remove(cmd);
1690
1691failed:
1692 hci_dev_unlock_bh(hdev);
1693 hci_dev_put(hdev);
1694
1695 return err;
1696}
1697
Antti Julku7fbec222011-06-15 12:01:15 +03001698static int block_device(struct sock *sk, u16 index, unsigned char *data,
1699 u16 len)
1700{
1701 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001702 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001703 int err;
1704
1705 BT_DBG("hci%u", index);
1706
Antti Julku7fbec222011-06-15 12:01:15 +03001707 if (len != sizeof(*cp))
1708 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1709 EINVAL);
1710
1711 hdev = hci_dev_get(index);
1712 if (!hdev)
1713 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1714 ENODEV);
1715
Antti Julku5e762442011-08-25 16:48:02 +03001716 hci_dev_lock_bh(hdev);
1717
Antti Julku7fbec222011-06-15 12:01:15 +03001718 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001719 if (err < 0)
1720 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1721 else
1722 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1723 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001724
Antti Julku5e762442011-08-25 16:48:02 +03001725 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001726 hci_dev_put(hdev);
1727
1728 return err;
1729}
1730
1731static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1732 u16 len)
1733{
1734 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001735 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001736 int err;
1737
1738 BT_DBG("hci%u", index);
1739
Antti Julku7fbec222011-06-15 12:01:15 +03001740 if (len != sizeof(*cp))
1741 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1742 EINVAL);
1743
1744 hdev = hci_dev_get(index);
1745 if (!hdev)
1746 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1747 ENODEV);
1748
Antti Julku5e762442011-08-25 16:48:02 +03001749 hci_dev_lock_bh(hdev);
1750
Antti Julku7fbec222011-06-15 12:01:15 +03001751 err = hci_blacklist_del(hdev, &cp->bdaddr);
1752
1753 if (err < 0)
1754 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1755 else
1756 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1757 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001758
Antti Julku5e762442011-08-25 16:48:02 +03001759 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001760 hci_dev_put(hdev);
1761
1762 return err;
1763}
1764
Antti Julkuf6422ec2011-06-22 13:11:56 +03001765static int set_fast_connectable(struct sock *sk, u16 index,
1766 unsigned char *data, u16 len)
1767{
1768 struct hci_dev *hdev;
1769 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1770 struct hci_cp_write_page_scan_activity acp;
1771 u8 type;
1772 int err;
1773
1774 BT_DBG("hci%u", index);
1775
1776 if (len != sizeof(*cp))
1777 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1778 EINVAL);
1779
1780 hdev = hci_dev_get(index);
1781 if (!hdev)
1782 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1783 ENODEV);
1784
1785 hci_dev_lock(hdev);
1786
1787 if (cp->enable) {
1788 type = PAGE_SCAN_TYPE_INTERLACED;
1789 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1790 } else {
1791 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1792 acp.interval = 0x0800; /* default 1.28 sec page scan */
1793 }
1794
1795 acp.window = 0x0012; /* default 11.25 msec page scan window */
1796
1797 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1798 sizeof(acp), &acp);
1799 if (err < 0) {
1800 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1801 -err);
1802 goto done;
1803 }
1804
1805 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1806 if (err < 0) {
1807 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1808 -err);
1809 goto done;
1810 }
1811
1812 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1813 NULL, 0);
1814done:
1815 hci_dev_unlock(hdev);
1816 hci_dev_put(hdev);
1817
1818 return err;
1819}
1820
Johan Hedberg03811012010-12-08 00:21:06 +02001821int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1822{
1823 unsigned char *buf;
1824 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001825 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001826 int err;
1827
1828 BT_DBG("got %zu bytes", msglen);
1829
1830 if (msglen < sizeof(*hdr))
1831 return -EINVAL;
1832
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001833 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001834 if (!buf)
1835 return -ENOMEM;
1836
1837 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1838 err = -EFAULT;
1839 goto done;
1840 }
1841
1842 hdr = (struct mgmt_hdr *) buf;
1843 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001844 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001845 len = get_unaligned_le16(&hdr->len);
1846
1847 if (len != msglen - sizeof(*hdr)) {
1848 err = -EINVAL;
1849 goto done;
1850 }
1851
1852 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001853 case MGMT_OP_READ_VERSION:
1854 err = read_version(sk);
1855 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001856 case MGMT_OP_READ_INDEX_LIST:
1857 err = read_index_list(sk);
1858 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001859 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001861 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001862 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001864 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001865 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001867 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001868 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001870 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001871 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001873 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001874 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 break;
1877 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001880 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 break;
1883 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001885 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001886 case MGMT_OP_LOAD_LINK_KEYS:
1887 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001889 case MGMT_OP_REMOVE_KEYS:
1890 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001892 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001895 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001896 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001897 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900 break;
1901 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001904 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001907 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001908 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001910 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001911 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 break;
1913 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001916 case MGMT_OP_SET_LOCAL_NAME:
1917 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1918 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001919 case MGMT_OP_READ_LOCAL_OOB_DATA:
1920 err = read_local_oob_data(sk, index);
1921 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001922 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1923 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1924 break;
1925 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1926 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1927 len);
1928 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001929 case MGMT_OP_START_DISCOVERY:
1930 err = start_discovery(sk, index);
1931 break;
1932 case MGMT_OP_STOP_DISCOVERY:
1933 err = stop_discovery(sk, index);
1934 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001935 case MGMT_OP_BLOCK_DEVICE:
1936 err = block_device(sk, index, buf + sizeof(*hdr), len);
1937 break;
1938 case MGMT_OP_UNBLOCK_DEVICE:
1939 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1940 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001941 case MGMT_OP_SET_FAST_CONNECTABLE:
1942 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1943 len);
1944 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001945 default:
1946 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001947 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001948 break;
1949 }
1950
Johan Hedberge41d8b42010-12-13 21:07:03 +02001951 if (err < 0)
1952 goto done;
1953
Johan Hedberg03811012010-12-08 00:21:06 +02001954 err = msglen;
1955
1956done:
1957 kfree(buf);
1958 return err;
1959}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001960
Johan Hedbergb24752f2011-11-03 14:40:33 +02001961static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1962{
1963 u8 *status = data;
1964
1965 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1966 mgmt_pending_remove(cmd);
1967}
1968
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001969int mgmt_index_added(u16 index)
1970{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001971 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001972}
1973
1974int mgmt_index_removed(u16 index)
1975{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001976 u8 status = ENODEV;
1977
1978 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1979
Szymon Janc4e51eae2011-02-25 19:05:48 +01001980 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001981}
1982
Johan Hedberg73f22f62010-12-29 16:00:25 +02001983struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001984 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985 struct sock *sk;
1986};
1987
Johan Hedberg72a734e2010-12-30 00:38:22 +02001988static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001989{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001990 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001991 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001992
Johan Hedberg72a734e2010-12-30 00:38:22 +02001993 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001994 return;
1995
Johan Hedberg053f0212011-01-26 13:07:10 +02001996 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001997
1998 list_del(&cmd->list);
1999
2000 if (match->sk == NULL) {
2001 match->sk = cmd->sk;
2002 sock_hold(match->sk);
2003 }
2004
2005 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002006}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002007
2008int mgmt_powered(u16 index, u8 powered)
2009{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002010 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002011 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002012 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002013
Johan Hedberg72a734e2010-12-30 00:38:22 +02002014 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002015
Johan Hedbergb24752f2011-11-03 14:40:33 +02002016 if (!powered) {
2017 u8 status = ENETDOWN;
2018 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2019 }
2020
Johan Hedberg72a734e2010-12-30 00:38:22 +02002021 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002022
Szymon Janc4e51eae2011-02-25 19:05:48 +01002023 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002024
2025 if (match.sk)
2026 sock_put(match.sk);
2027
2028 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002029}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002030
Johan Hedberg73f22f62010-12-29 16:00:25 +02002031int mgmt_discoverable(u16 index, u8 discoverable)
2032{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002033 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002034 struct cmd_lookup match = { discoverable, NULL };
2035 int ret;
2036
Szymon Jancb8534e02011-03-01 16:55:34 +01002037 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002038
Johan Hedberg72a734e2010-12-30 00:38:22 +02002039 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002040
Szymon Janc4e51eae2011-02-25 19:05:48 +01002041 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2042 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002043
2044 if (match.sk)
2045 sock_put(match.sk);
2046
2047 return ret;
2048}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002049
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002050int mgmt_connectable(u16 index, u8 connectable)
2051{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002052 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002053 struct cmd_lookup match = { connectable, NULL };
2054 int ret;
2055
Johan Hedberg72a734e2010-12-30 00:38:22 +02002056 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002057
Johan Hedberg72a734e2010-12-30 00:38:22 +02002058 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002059
Szymon Janc4e51eae2011-02-25 19:05:48 +01002060 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002061
2062 if (match.sk)
2063 sock_put(match.sk);
2064
2065 return ret;
2066}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002067
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002068int mgmt_write_scan_failed(u16 index, u8 scan, u8 status)
2069{
2070 if (scan & SCAN_PAGE)
2071 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index,
2072 cmd_status_rsp, &status);
2073
2074 if (scan & SCAN_INQUIRY)
2075 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
2076 cmd_status_rsp, &status);
2077
2078 return 0;
2079}
2080
Johan Hedberg86742e12011-11-07 23:13:38 +02002081int mgmt_new_link_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002082{
Johan Hedberg86742e12011-11-07 23:13:38 +02002083 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002084
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002085 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002086
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002087 ev.store_hint = persistent;
2088 bacpy(&ev.key.bdaddr, &key->bdaddr);
2089 ev.key.type = key->type;
2090 memcpy(ev.key.val, key->val, 16);
2091 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002092
Johan Hedberg86742e12011-11-07 23:13:38 +02002093 return mgmt_event(MGMT_EV_NEW_LINK_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002094}
Johan Hedbergf7520542011-01-20 12:34:39 +02002095
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002096int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002097{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002098 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002099
Johan Hedbergf7520542011-01-20 12:34:39 +02002100 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002101 ev.type = link_to_mgmt(link_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002102
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002104}
2105
Johan Hedberg8962ee72011-01-20 12:40:27 +02002106static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2107{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002108 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002109 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002110 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002111
Johan Hedberga38528f2011-01-22 06:46:43 +02002112 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113
Szymon Janc4e51eae2011-02-25 19:05:48 +01002114 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002115
2116 *sk = cmd->sk;
2117 sock_hold(*sk);
2118
Johan Hedberga664b5b2011-02-19 12:06:02 -03002119 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002120}
2121
Johan Hedberg4c659c32011-11-07 23:13:39 +02002122int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002123{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002124 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002125 struct sock *sk = NULL;
2126 int err;
2127
2128 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002129
Johan Hedbergf7520542011-01-20 12:34:39 +02002130 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002131 ev.type = link_to_mgmt(type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002132
Szymon Janc4e51eae2011-02-25 19:05:48 +01002133 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002134
2135 if (sk)
2136 sock_put(sk);
2137
2138 return err;
2139}
2140
2141int mgmt_disconnect_failed(u16 index)
2142{
2143 struct pending_cmd *cmd;
2144 int err;
2145
2146 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2147 if (!cmd)
2148 return -ENOENT;
2149
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002151
Johan Hedberga664b5b2011-02-19 12:06:02 -03002152 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002153
2154 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002155}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002156
Johan Hedberg4c659c32011-11-07 23:13:39 +02002157int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002158{
2159 struct mgmt_ev_connect_failed ev;
2160
Johan Hedberg4c659c32011-11-07 23:13:39 +02002161 bacpy(&ev.addr.bdaddr, bdaddr);
2162 ev.addr.type = link_to_mgmt(type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002163 ev.status = status;
2164
Szymon Janc4e51eae2011-02-25 19:05:48 +01002165 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002166}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002167
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002168int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002169{
2170 struct mgmt_ev_pin_code_request ev;
2171
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002173 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174
Szymon Janc4e51eae2011-02-25 19:05:48 +01002175 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2176 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177}
2178
2179int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2180{
2181 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002182 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002183 int err;
2184
2185 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2186 if (!cmd)
2187 return -ENOENT;
2188
Johan Hedbergac56fb12011-02-19 12:05:59 -03002189 bacpy(&rp.bdaddr, bdaddr);
2190 rp.status = status;
2191
Szymon Janc4e51eae2011-02-25 19:05:48 +01002192 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2193 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002194
Johan Hedberga664b5b2011-02-19 12:06:02 -03002195 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002196
2197 return err;
2198}
2199
2200int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2201{
2202 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002203 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002204 int err;
2205
2206 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2207 if (!cmd)
2208 return -ENOENT;
2209
Johan Hedbergac56fb12011-02-19 12:05:59 -03002210 bacpy(&rp.bdaddr, bdaddr);
2211 rp.status = status;
2212
Szymon Janc4e51eae2011-02-25 19:05:48 +01002213 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2214 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002215
Johan Hedberga664b5b2011-02-19 12:06:02 -03002216 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002217
2218 return err;
2219}
Johan Hedberga5c29682011-02-19 12:05:57 -03002220
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002221int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2222 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002223{
2224 struct mgmt_ev_user_confirm_request ev;
2225
2226 BT_DBG("hci%u", index);
2227
Johan Hedberga5c29682011-02-19 12:05:57 -03002228 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002229 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002230 put_unaligned_le32(value, &ev.value);
2231
Szymon Janc4e51eae2011-02-25 19:05:48 +01002232 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2233 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002234}
2235
2236static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2237 u8 opcode)
2238{
2239 struct pending_cmd *cmd;
2240 struct mgmt_rp_user_confirm_reply rp;
2241 int err;
2242
2243 cmd = mgmt_pending_find(opcode, index);
2244 if (!cmd)
2245 return -ENOENT;
2246
Johan Hedberga5c29682011-02-19 12:05:57 -03002247 bacpy(&rp.bdaddr, bdaddr);
2248 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002249 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002250
Johan Hedberga664b5b2011-02-19 12:06:02 -03002251 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002252
2253 return err;
2254}
2255
2256int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2257{
2258 return confirm_reply_complete(index, bdaddr, status,
2259 MGMT_OP_USER_CONFIRM_REPLY);
2260}
2261
Szymon Jancb8534e02011-03-01 16:55:34 +01002262int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002263{
2264 return confirm_reply_complete(index, bdaddr, status,
2265 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2266}
Johan Hedberg2a611692011-02-19 12:06:00 -03002267
2268int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2269{
2270 struct mgmt_ev_auth_failed ev;
2271
Johan Hedberg2a611692011-02-19 12:06:00 -03002272 bacpy(&ev.bdaddr, bdaddr);
2273 ev.status = status;
2274
Szymon Janc4e51eae2011-02-25 19:05:48 +01002275 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002276}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002277
2278int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2279{
2280 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002281 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002282 struct mgmt_cp_set_local_name ev;
2283 int err;
2284
2285 memset(&ev, 0, sizeof(ev));
2286 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2287
2288 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2289 if (!cmd)
2290 goto send_event;
2291
2292 if (status) {
2293 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2294 goto failed;
2295 }
2296
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002297 hdev = hci_dev_get(index);
2298 if (hdev) {
2299 hci_dev_lock_bh(hdev);
2300 update_eir(hdev);
2301 hci_dev_unlock_bh(hdev);
2302 hci_dev_put(hdev);
2303 }
2304
Johan Hedbergb312b1612011-03-16 14:29:37 +02002305 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2306 sizeof(ev));
2307 if (err < 0)
2308 goto failed;
2309
2310send_event:
2311 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2312 cmd ? cmd->sk : NULL);
2313
2314failed:
2315 if (cmd)
2316 mgmt_pending_remove(cmd);
2317 return err;
2318}
Szymon Jancc35938b2011-03-22 13:12:21 +01002319
2320int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2321 u8 status)
2322{
2323 struct pending_cmd *cmd;
2324 int err;
2325
2326 BT_DBG("hci%u status %u", index, status);
2327
2328 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2329 if (!cmd)
2330 return -ENOENT;
2331
2332 if (status) {
2333 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2334 EIO);
2335 } else {
2336 struct mgmt_rp_read_local_oob_data rp;
2337
2338 memcpy(rp.hash, hash, sizeof(rp.hash));
2339 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2340
2341 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2342 &rp, sizeof(rp));
2343 }
2344
2345 mgmt_pending_remove(cmd);
2346
2347 return err;
2348}
Johan Hedberge17acd42011-03-30 23:57:16 +03002349
Johan Hedberg4c659c32011-11-07 23:13:39 +02002350int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 *dev_class,
2351 s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002352{
2353 struct mgmt_ev_device_found ev;
2354
2355 memset(&ev, 0, sizeof(ev));
2356
Johan Hedberg4c659c32011-11-07 23:13:39 +02002357 bacpy(&ev.addr.bdaddr, bdaddr);
2358 ev.addr.type = link_to_mgmt(type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002359 ev.rssi = rssi;
2360
2361 if (eir)
2362 memcpy(ev.eir, eir, sizeof(ev.eir));
2363
Andre Guedesf8523592011-09-09 18:56:26 -03002364 if (dev_class)
2365 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2366
Johan Hedberge17acd42011-03-30 23:57:16 +03002367 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2368}
Johan Hedberga88a9652011-03-30 13:18:12 +03002369
2370int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2371{
2372 struct mgmt_ev_remote_name ev;
2373
2374 memset(&ev, 0, sizeof(ev));
2375
2376 bacpy(&ev.bdaddr, bdaddr);
2377 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2378
2379 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2380}
Johan Hedberg314b2382011-04-27 10:29:57 -04002381
Johan Hedberg164a6e72011-11-01 17:06:44 +02002382int mgmt_inquiry_failed(u16 index, u8 status)
2383{
2384 struct pending_cmd *cmd;
2385 int err;
2386
2387 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2388 if (!cmd)
2389 return -ENOENT;
2390
2391 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2392 mgmt_pending_remove(cmd);
2393
2394 return err;
2395}
2396
Johan Hedberg314b2382011-04-27 10:29:57 -04002397int mgmt_discovering(u16 index, u8 discovering)
2398{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002399 struct pending_cmd *cmd;
2400
2401 if (discovering)
2402 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2403 else
2404 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2405
2406 if (cmd != NULL) {
2407 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2408 mgmt_pending_remove(cmd);
2409 }
2410
Johan Hedberg314b2382011-04-27 10:29:57 -04002411 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2412 sizeof(discovering), NULL);
2413}
Antti Julku5e762442011-08-25 16:48:02 +03002414
2415int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2416{
2417 struct pending_cmd *cmd;
2418 struct mgmt_ev_device_blocked ev;
2419
2420 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2421
2422 bacpy(&ev.bdaddr, bdaddr);
2423
2424 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2425 cmd ? cmd->sk : NULL);
2426}
2427
2428int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2429{
2430 struct pending_cmd *cmd;
2431 struct mgmt_ev_device_unblocked ev;
2432
2433 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2434
2435 bacpy(&ev.bdaddr, bdaddr);
2436
2437 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2438 cmd ? cmd->sk : NULL);
2439}