blob: 579f7261a7fe3d72593dde8ad8a99b3f3660333d [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
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
Johannes Bergb5ad8b72011-06-01 08:54:45 +020044static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
Szymon Janc34eb5252011-02-28 14:10:08 +010052 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020053
54 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
55 if (!skb)
56 return -ENOMEM;
57
58 hdr = (void *) skb_put(skb, sizeof(*hdr));
59
60 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010061 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020062 hdr->len = cpu_to_le16(sizeof(*ev));
63
64 ev = (void *) skb_put(skb, sizeof(*ev));
65 ev->status = status;
66 put_unaligned_le16(cmd, &ev->opcode);
67
68 if (sock_queue_rcv_skb(sk, skb) < 0)
69 kfree_skb(skb);
70
71 return 0;
72}
73
Szymon Janc4e51eae2011-02-25 19:05:48 +010074static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
75 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020076{
77 struct sk_buff *skb;
78 struct mgmt_hdr *hdr;
79 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020080
81 BT_DBG("sock %p", sk);
82
Johan Hedberga38528f2011-01-22 06:46:43 +020083 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020084 if (!skb)
85 return -ENOMEM;
86
87 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020088
Johan Hedberg02d98122010-12-13 21:07:04 +020089 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010090 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020091 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020092
Johan Hedberga38528f2011-01-22 06:46:43 +020093 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
94 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010095
96 if (rp)
97 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020098
99 if (sock_queue_rcv_skb(sk, skb) < 0)
100 kfree_skb(skb);
101
102 return 0;
103}
104
Johan Hedberga38528f2011-01-22 06:46:43 +0200105static int read_version(struct sock *sk)
106{
107 struct mgmt_rp_read_version rp;
108
109 BT_DBG("sock %p", sk);
110
111 rp.version = MGMT_VERSION;
112 put_unaligned_le16(MGMT_REVISION, &rp.revision);
113
Szymon Janc4e51eae2011-02-25 19:05:48 +0100114 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
115 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200116}
117
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200118static int read_index_list(struct sock *sk)
119{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200120 struct mgmt_rp_read_index_list *rp;
121 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200122 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200123 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200124 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200125
126 BT_DBG("sock %p", sk);
127
128 read_lock(&hci_dev_list_lock);
129
130 count = 0;
131 list_for_each(p, &hci_dev_list) {
132 count++;
133 }
134
Johan Hedberga38528f2011-01-22 06:46:43 +0200135 rp_len = sizeof(*rp) + (2 * count);
136 rp = kmalloc(rp_len, GFP_ATOMIC);
137 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100138 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100140 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200141
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142 put_unaligned_le16(count, &rp->num_controllers);
143
144 i = 0;
145 list_for_each(p, &hci_dev_list) {
146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200147
148 hci_del_off_timer(d);
149
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200150 set_bit(HCI_MGMT, &d->flags);
151
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200152 if (test_bit(HCI_SETUP, &d->flags))
153 continue;
154
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200155 put_unaligned_le16(d->id, &rp->index[i++]);
156 BT_DBG("Added hci%u", d->id);
157 }
158
159 read_unlock(&hci_dev_list_lock);
160
Szymon Janc4e51eae2011-02-25 19:05:48 +0100161 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
162 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200163
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 kfree(rp);
165
166 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200167}
168
Szymon Janc4e51eae2011-02-25 19:05:48 +0100169static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200170{
Johan Hedberga38528f2011-01-22 06:46:43 +0200171 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200172 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200173
Szymon Janc4e51eae2011-02-25 19:05:48 +0100174 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200175
Szymon Janc4e51eae2011-02-25 19:05:48 +0100176 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200177 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200179
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200180 hci_del_off_timer(hdev);
181
Andre Guedes8c156c32011-07-07 10:30:36 -0300182 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200183
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200184 set_bit(HCI_MGMT, &hdev->flags);
185
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200186 memset(&rp, 0, sizeof(rp));
187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200189
Johan Hedberga38528f2011-01-22 06:46:43 +0200190 rp.powered = test_bit(HCI_UP, &hdev->flags);
191 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
192 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
193 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200194
195 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 bacpy(&rp.bdaddr, &hdev->bdaddr);
203 memcpy(rp.features, hdev->features, 8);
204 memcpy(rp.dev_class, hdev->dev_class, 3);
205 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
206 rp.hci_ver = hdev->hci_ver;
207 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200209 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
210
Andre Guedes8c156c32011-07-07 10:30:36 -0300211 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200213
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200215}
216
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200217static void mgmt_pending_free(struct pending_cmd *cmd)
218{
219 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100220 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200221 kfree(cmd);
222}
223
Johan Hedberg366a0332011-02-19 12:05:55 -0300224static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
225 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200226{
227 struct pending_cmd *cmd;
228
229 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
230 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300231 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200232
233 cmd->opcode = opcode;
234 cmd->index = index;
235
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100236 cmd->param = kmalloc(len, GFP_ATOMIC);
237 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200238 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300239 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200240 }
241
Szymon Janc8fce6352011-03-22 13:12:20 +0100242 if (data)
243 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244
245 cmd->sk = sk;
246 sock_hold(sk);
247
248 list_add(&cmd->list, &cmd_list);
249
Johan Hedberg366a0332011-02-19 12:05:55 -0300250 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200251}
252
253static void mgmt_pending_foreach(u16 opcode, int index,
254 void (*cb)(struct pending_cmd *cmd, void *data),
255 void *data)
256{
257 struct list_head *p, *n;
258
259 list_for_each_safe(p, n, &cmd_list) {
260 struct pending_cmd *cmd;
261
262 cmd = list_entry(p, struct pending_cmd, list);
263
264 if (cmd->opcode != opcode)
265 continue;
266
267 if (index >= 0 && cmd->index != index)
268 continue;
269
270 cb(cmd, data);
271 }
272}
273
274static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
275{
276 struct list_head *p;
277
278 list_for_each(p, &cmd_list) {
279 struct pending_cmd *cmd;
280
281 cmd = list_entry(p, struct pending_cmd, list);
282
283 if (cmd->opcode != opcode)
284 continue;
285
286 if (index >= 0 && cmd->index != index)
287 continue;
288
289 return cmd;
290 }
291
292 return NULL;
293}
294
Johan Hedberga664b5b2011-02-19 12:06:02 -0300295static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297 list_del(&cmd->list);
298 mgmt_pending_free(cmd);
299}
300
Szymon Janc4e51eae2011-02-25 19:05:48 +0100301static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200303 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200307
308 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200309
Szymon Janc4e51eae2011-02-25 19:05:48 +0100310 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100312 if (len != sizeof(*cp))
313 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
314
Szymon Janc4e51eae2011-02-25 19:05:48 +0100315 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100317 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200318
Andre Guedes8c156c32011-07-07 10:30:36 -0300319 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200320
321 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200322 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 goto failed;
325 }
326
Szymon Janc4e51eae2011-02-25 19:05:48 +0100327 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
328 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 goto failed;
330 }
331
Szymon Janc4e51eae2011-02-25 19:05:48 +0100332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 if (!cmd) {
334 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300336 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Johan Hedberg72a734e2010-12-30 00:38:22 +0200338 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 queue_work(hdev->workqueue, &hdev->power_on);
340 else
341 queue_work(hdev->workqueue, &hdev->power_off);
342
Johan Hedberg366a0332011-02-19 12:05:55 -0300343 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344
345failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300346 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200347 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200349}
350
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
352 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200354 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300356 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357 u8 scan;
358 int err;
359
360 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100364 if (len != sizeof(*cp))
365 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
366
Szymon Janc4e51eae2011-02-25 19:05:48 +0100367 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200370
Andre Guedes8c156c32011-07-07 10:30:36 -0300371 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200375 goto failed;
376 }
377
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
380 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 goto failed;
382 }
383
Johan Hedberg72a734e2010-12-30 00:38:22 +0200384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387 goto failed;
388 }
389
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 if (!cmd) {
392 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
396 scan = SCAN_PAGE;
397
Johan Hedberg72a734e2010-12-30 00:38:22 +0200398 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399 scan |= SCAN_INQUIRY;
400
401 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
402 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300403 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404
405failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300406 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200407 hci_dev_put(hdev);
408
409 return err;
410}
411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
413 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200414{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200415 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200416 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300417 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418 u8 scan;
419 int err;
420
421 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100425 if (len != sizeof(*cp))
426 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
427
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431
Andre Guedes8c156c32011-07-07 10:30:36 -0300432 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433
434 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200436 goto failed;
437 }
438
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100446 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200447 goto failed;
448 }
449
Szymon Janc4e51eae2011-02-25 19:05:48 +0100450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 if (!cmd) {
452 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300454 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200455
Johan Hedberg72a734e2010-12-30 00:38:22 +0200456 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 scan = SCAN_PAGE;
458 else
459 scan = 0;
460
461 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
462 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300463 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464
465failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300466 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200467 hci_dev_put(hdev);
468
469 return err;
470}
471
Szymon Janc4e51eae2011-02-25 19:05:48 +0100472static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
473 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200474{
475 struct sk_buff *skb;
476 struct mgmt_hdr *hdr;
477
478 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
479 if (!skb)
480 return -ENOMEM;
481
482 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
483
484 hdr = (void *) skb_put(skb, sizeof(*hdr));
485 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100486 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200487 hdr->len = cpu_to_le16(data_len);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
Johan Hedberg053f0212011-01-26 13:07:10 +0200498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200501
Johan Hedberga38528f2011-01-22 06:46:43 +0200502 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200505}
506
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512 int err;
513
514 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
Szymon Janc4e51eae2011-02-25 19:05:48 +0100521 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200522 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
Andre Guedes8c156c32011-07-07 10:30:36 -0300525 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 if (err < 0)
534 goto failed;
535
Johan Hedbergc542a062011-01-26 13:11:03 +0200536 ev.val = cp->val;
537
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539
540failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300541 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 hci_dev_put(hdev);
543
544 return err;
545}
546
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547#define EIR_FLAGS 0x01 /* flags */
548#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
549#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
550#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
551#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
552#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
553#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
554#define EIR_NAME_SHORT 0x08 /* shortened local name */
555#define EIR_NAME_COMPLETE 0x09 /* complete local name */
556#define EIR_TX_POWER 0x0A /* transmit power level */
557#define EIR_DEVICE_ID 0x10 /* device ID */
558
559#define PNP_INFO_SVCLASS_ID 0x1200
560
561static u8 bluetooth_base_uuid[] = {
562 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564};
565
566static u16 get_uuid16(u8 *uuid128)
567{
568 u32 val;
569 int i;
570
571 for (i = 0; i < 12; i++) {
572 if (bluetooth_base_uuid[i] != uuid128[i])
573 return 0;
574 }
575
576 memcpy(&val, &uuid128[12], 4);
577
578 val = le32_to_cpu(val);
579 if (val > 0xffff)
580 return 0;
581
582 return (u16) val;
583}
584
585static void create_eir(struct hci_dev *hdev, u8 *data)
586{
587 u8 *ptr = data;
588 u16 eir_len = 0;
589 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
590 int i, truncated = 0;
591 struct list_head *p;
592 size_t name_len;
593
594 name_len = strlen(hdev->dev_name);
595
596 if (name_len > 0) {
597 /* EIR Data type */
598 if (name_len > 48) {
599 name_len = 48;
600 ptr[1] = EIR_NAME_SHORT;
601 } else
602 ptr[1] = EIR_NAME_COMPLETE;
603
604 /* EIR Data length */
605 ptr[0] = name_len + 1;
606
607 memcpy(ptr + 2, hdev->dev_name, name_len);
608
609 eir_len += (name_len + 2);
610 ptr += (name_len + 2);
611 }
612
613 memset(uuid16_list, 0, sizeof(uuid16_list));
614
615 /* Group all UUID16 types */
616 list_for_each(p, &hdev->uuids) {
617 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
618 u16 uuid16;
619
620 uuid16 = get_uuid16(uuid->uuid);
621 if (uuid16 == 0)
622 return;
623
624 if (uuid16 < 0x1100)
625 continue;
626
627 if (uuid16 == PNP_INFO_SVCLASS_ID)
628 continue;
629
630 /* Stop if not enough space to put next UUID */
631 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
632 truncated = 1;
633 break;
634 }
635
636 /* Check for duplicates */
637 for (i = 0; uuid16_list[i] != 0; i++)
638 if (uuid16_list[i] == uuid16)
639 break;
640
641 if (uuid16_list[i] == 0) {
642 uuid16_list[i] = uuid16;
643 eir_len += sizeof(u16);
644 }
645 }
646
647 if (uuid16_list[0] != 0) {
648 u8 *length = ptr;
649
650 /* EIR Data type */
651 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
652
653 ptr += 2;
654 eir_len += 2;
655
656 for (i = 0; uuid16_list[i] != 0; i++) {
657 *ptr++ = (uuid16_list[i] & 0x00ff);
658 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
659 }
660
661 /* EIR Data length */
662 *length = (i * sizeof(u16)) + 1;
663 }
664}
665
666static int update_eir(struct hci_dev *hdev)
667{
668 struct hci_cp_write_eir cp;
669
670 if (!(hdev->features[6] & LMP_EXT_INQ))
671 return 0;
672
673 if (hdev->ssp_mode == 0)
674 return 0;
675
676 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
677 return 0;
678
679 memset(&cp, 0, sizeof(cp));
680
681 create_eir(hdev, cp.data);
682
683 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
684 return 0;
685
686 memcpy(hdev->eir, cp.data, sizeof(cp.data));
687
688 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
689}
690
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200691static u8 get_service_classes(struct hci_dev *hdev)
692{
693 struct list_head *p;
694 u8 val = 0;
695
696 list_for_each(p, &hdev->uuids) {
697 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
698
699 val |= uuid->svc_hint;
700 }
701
702 return val;
703}
704
705static int update_class(struct hci_dev *hdev)
706{
707 u8 cod[3];
708
709 BT_DBG("%s", hdev->name);
710
711 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
712 return 0;
713
714 cod[0] = hdev->minor_class;
715 cod[1] = hdev->major_class;
716 cod[2] = get_service_classes(hdev);
717
718 if (memcmp(cod, hdev->dev_class, 3) == 0)
719 return 0;
720
721 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
722}
723
Szymon Janc4e51eae2011-02-25 19:05:48 +0100724static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725{
726 struct mgmt_cp_add_uuid *cp;
727 struct hci_dev *hdev;
728 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729 int err;
730
731 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200732
Szymon Janc4e51eae2011-02-25 19:05:48 +0100733 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100735 if (len != sizeof(*cp))
736 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741
Andre Guedes8c156c32011-07-07 10:30:36 -0300742 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743
744 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
745 if (!uuid) {
746 err = -ENOMEM;
747 goto failed;
748 }
749
750 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200751 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200752
753 list_add(&uuid->list, &hdev->uuids);
754
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755 err = update_class(hdev);
756 if (err < 0)
757 goto failed;
758
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300759 err = update_eir(hdev);
760 if (err < 0)
761 goto failed;
762
Szymon Janc4e51eae2011-02-25 19:05:48 +0100763 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200764
765failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300766 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200767 hci_dev_put(hdev);
768
769 return err;
770}
771
Szymon Janc4e51eae2011-02-25 19:05:48 +0100772static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200773{
774 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100775 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200776 struct hci_dev *hdev;
777 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778 int err, found;
779
780 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781
Szymon Janc4e51eae2011-02-25 19:05:48 +0100782 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100784 if (len != sizeof(*cp))
785 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
786
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100789 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790
Andre Guedes8c156c32011-07-07 10:30:36 -0300791 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792
793 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
794 err = hci_uuids_clear(hdev);
795 goto unlock;
796 }
797
798 found = 0;
799
800 list_for_each_safe(p, n, &hdev->uuids) {
801 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
802
803 if (memcmp(match->uuid, cp->uuid, 16) != 0)
804 continue;
805
806 list_del(&match->list);
807 found++;
808 }
809
810 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200812 goto unlock;
813 }
814
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200815 err = update_class(hdev);
816 if (err < 0)
817 goto unlock;
818
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300819 err = update_eir(hdev);
820 if (err < 0)
821 goto unlock;
822
Szymon Janc4e51eae2011-02-25 19:05:48 +0100823 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200824
825unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300826 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200827 hci_dev_put(hdev);
828
829 return err;
830}
831
Szymon Janc4e51eae2011-02-25 19:05:48 +0100832static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
833 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200834{
835 struct hci_dev *hdev;
836 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200837 int err;
838
839 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100843 if (len != sizeof(*cp))
844 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
845
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849
Andre Guedes8c156c32011-07-07 10:30:36 -0300850 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851
852 hdev->major_class = cp->major;
853 hdev->minor_class = cp->minor;
854
855 err = update_class(hdev);
856
857 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100858 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200859
Andre Guedes8c156c32011-07-07 10:30:36 -0300860 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861 hci_dev_put(hdev);
862
863 return err;
864}
865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
867 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200868{
869 struct hci_dev *hdev;
870 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200871 int err;
872
873 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200874
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100875 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100876 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100877
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
Andre Guedes8c156c32011-07-07 10:30:36 -0300882 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
886 if (cp->enable) {
887 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
888 err = 0;
889 } else {
890 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
891 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300892 if (err == 0)
893 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200894 }
895
896 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100897 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
898 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899
Andre Guedes8c156c32011-07-07 10:30:36 -0300900 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200901 hci_dev_put(hdev);
902
903 return err;
904}
905
Szymon Janc4e51eae2011-02-25 19:05:48 +0100906static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200907{
908 struct hci_dev *hdev;
909 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 u16 key_count, expected_len;
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300911 int i, err;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200912
913 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100914
915 if (len < sizeof(*cp))
916 return -EINVAL;
917
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200918 key_count = get_unaligned_le16(&cp->key_count);
919
920 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300921 if (expected_len > len) {
922 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
923 expected_len, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200924 return -EINVAL;
925 }
926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200930
Szymon Janc4e51eae2011-02-25 19:05:48 +0100931 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200932 key_count);
933
Andre Guedes8c156c32011-07-07 10:30:36 -0300934 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935
936 hci_link_keys_clear(hdev);
937
938 set_bit(HCI_LINK_KEYS, &hdev->flags);
939
940 if (cp->debug_keys)
941 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
942 else
943 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
944
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300945 len -= sizeof(*cp);
946 i = 0;
947
948 while (i < len) {
949 struct mgmt_key_info *key = (void *) cp->keys + i;
950
951 i += sizeof(*key) + key->dlen;
952
953 if (key->type == HCI_LK_SMP_LTK) {
954 struct key_master_id *id = (void *) key->data;
955
956 if (key->dlen != sizeof(struct key_master_id))
957 continue;
958
Vinicius Costa Gomes726b4ff2011-07-08 18:31:45 -0300959 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
960 id->ediv, id->rand, key->val);
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300961
962 continue;
963 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200964
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700965 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200966 key->pin_len);
967 }
968
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300969 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
970
Andre Guedes8c156c32011-07-07 10:30:36 -0300971 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200972 hci_dev_put(hdev);
973
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -0300974 return err;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200975}
976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978{
979 struct hci_dev *hdev;
980 struct mgmt_cp_remove_key *cp;
981 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200982 int err;
983
984 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200985
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100986 if (len != sizeof(*cp))
987 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
988
Szymon Janc4e51eae2011-02-25 19:05:48 +0100989 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200990 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100991 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200992
Andre Guedes8c156c32011-07-07 10:30:36 -0300993 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200994
995 err = hci_remove_link_key(hdev, &cp->bdaddr);
996 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100997 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200998 goto unlock;
999 }
1000
1001 err = 0;
1002
1003 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1004 goto unlock;
1005
1006 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1007 if (conn) {
1008 struct hci_cp_disconnect dc;
1009
1010 put_unaligned_le16(conn->handle, &dc.handle);
1011 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -04001012 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001013 }
1014
1015unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001016 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001017 hci_dev_put(hdev);
1018
1019 return err;
1020}
1021
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023{
1024 struct hci_dev *hdev;
1025 struct mgmt_cp_disconnect *cp;
1026 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001027 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001029 int err;
1030
1031 BT_DBG("");
1032
1033 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001034
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001035 if (len != sizeof(*cp))
1036 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1037
Szymon Janc4e51eae2011-02-25 19:05:48 +01001038 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001039 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001040 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001041
Andre Guedes8c156c32011-07-07 10:30:36 -03001042 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001043
1044 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046 goto failed;
1047 }
1048
Szymon Janc4e51eae2011-02-25 19:05:48 +01001049 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1050 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001051 goto failed;
1052 }
1053
1054 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001055 if (!conn)
1056 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1057
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001059 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001060 goto failed;
1061 }
1062
Szymon Janc4e51eae2011-02-25 19:05:48 +01001063 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001064 if (!cmd) {
1065 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001066 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001067 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001068
1069 put_unaligned_le16(conn->handle, &dc.handle);
1070 dc.reason = 0x13; /* Remote User Terminated Connection */
1071
1072 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1073 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001074 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001075
1076failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001077 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001078 hci_dev_put(hdev);
1079
1080 return err;
1081}
1082
Szymon Janc8ce62842011-03-01 16:55:32 +01001083static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001084{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001085 struct mgmt_rp_get_connections *rp;
1086 struct hci_dev *hdev;
1087 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001088 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001089 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001090 int i, err;
1091
1092 BT_DBG("");
1093
Szymon Janc4e51eae2011-02-25 19:05:48 +01001094 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001095 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001096 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097
Andre Guedes8c156c32011-07-07 10:30:36 -03001098 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099
1100 count = 0;
1101 list_for_each(p, &hdev->conn_hash.list) {
1102 count++;
1103 }
1104
Johan Hedberga38528f2011-01-22 06:46:43 +02001105 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1106 rp = kmalloc(rp_len, GFP_ATOMIC);
1107 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001108 err = -ENOMEM;
1109 goto unlock;
1110 }
1111
Johan Hedberg2784eb42011-01-21 13:56:35 +02001112 put_unaligned_le16(count, &rp->conn_count);
1113
Johan Hedberg2784eb42011-01-21 13:56:35 +02001114 i = 0;
1115 list_for_each(p, &hdev->conn_hash.list) {
1116 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1117
1118 bacpy(&rp->conn[i++], &c->dst);
1119 }
1120
Szymon Janc4e51eae2011-02-25 19:05:48 +01001121 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001122
1123unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001124 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001125 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001126 hci_dev_put(hdev);
1127 return err;
1128}
1129
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001130static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1131 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1132{
1133 struct pending_cmd *cmd;
1134 int err;
1135
1136 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1137 sizeof(*cp));
1138 if (!cmd)
1139 return -ENOMEM;
1140
1141 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1142 &cp->bdaddr);
1143 if (err < 0)
1144 mgmt_pending_remove(cmd);
1145
1146 return err;
1147}
1148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1150 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001151{
1152 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001153 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001155 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001156 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001157 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001158 int err;
1159
1160 BT_DBG("");
1161
1162 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001163
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001164 if (len != sizeof(*cp))
1165 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1166
Szymon Janc4e51eae2011-02-25 19:05:48 +01001167 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001168 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001169 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001170
Andre Guedes8c156c32011-07-07 10:30:36 -03001171 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001172
1173 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001174 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001175 goto failed;
1176 }
1177
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001178 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1179 if (!conn) {
1180 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1181 goto failed;
1182 }
1183
1184 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1185 bacpy(&ncp.bdaddr, &cp->bdaddr);
1186
1187 BT_ERR("PIN code is not 16 bytes long");
1188
1189 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1190 if (err >= 0)
1191 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1192 EINVAL);
1193
1194 goto failed;
1195 }
1196
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001198 if (!cmd) {
1199 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001201 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202
1203 bacpy(&reply.bdaddr, &cp->bdaddr);
1204 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001205 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001206
1207 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1208 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001209 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
1211failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001212 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001213 hci_dev_put(hdev);
1214
1215 return err;
1216}
1217
Szymon Janc4e51eae2011-02-25 19:05:48 +01001218static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1219 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001220{
1221 struct hci_dev *hdev;
1222 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001223 int err;
1224
1225 BT_DBG("");
1226
1227 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001229 if (len != sizeof(*cp))
1230 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1231 EINVAL);
1232
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1236 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001237
Andre Guedes8c156c32011-07-07 10:30:36 -03001238 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001239
1240 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001241 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1242 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001243 goto failed;
1244 }
1245
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001246 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001247
1248failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001249 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001250 hci_dev_put(hdev);
1251
1252 return err;
1253}
1254
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1256 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001257{
1258 struct hci_dev *hdev;
1259 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260
1261 BT_DBG("");
1262
1263 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001264
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001265 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001266 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001267
Szymon Janc4e51eae2011-02-25 19:05:48 +01001268 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001269 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001270 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001271
Andre Guedes8c156c32011-07-07 10:30:36 -03001272 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001273
1274 hdev->io_capability = cp->io_capability;
1275
1276 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001277 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001278
Andre Guedes8c156c32011-07-07 10:30:36 -03001279 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001280 hci_dev_put(hdev);
1281
Szymon Janc4e51eae2011-02-25 19:05:48 +01001282 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001283}
1284
Johan Hedberge9a416b2011-02-19 12:05:56 -03001285static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1286{
1287 struct hci_dev *hdev = conn->hdev;
1288 struct list_head *p;
1289
1290 list_for_each(p, &cmd_list) {
1291 struct pending_cmd *cmd;
1292
1293 cmd = list_entry(p, struct pending_cmd, list);
1294
1295 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1296 continue;
1297
1298 if (cmd->index != hdev->id)
1299 continue;
1300
1301 if (cmd->user_data != conn)
1302 continue;
1303
1304 return cmd;
1305 }
1306
1307 return NULL;
1308}
1309
1310static void pairing_complete(struct pending_cmd *cmd, u8 status)
1311{
1312 struct mgmt_rp_pair_device rp;
1313 struct hci_conn *conn = cmd->user_data;
1314
Johan Hedberge9a416b2011-02-19 12:05:56 -03001315 bacpy(&rp.bdaddr, &conn->dst);
1316 rp.status = status;
1317
Szymon Janc4e51eae2011-02-25 19:05:48 +01001318 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001319
1320 /* So we don't get further callbacks for this connection */
1321 conn->connect_cfm_cb = NULL;
1322 conn->security_cfm_cb = NULL;
1323 conn->disconn_cfm_cb = NULL;
1324
1325 hci_conn_put(conn);
1326
Johan Hedberga664b5b2011-02-19 12:06:02 -03001327 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001328}
1329
1330static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1331{
1332 struct pending_cmd *cmd;
1333
1334 BT_DBG("status %u", status);
1335
1336 cmd = find_pairing(conn);
1337 if (!cmd) {
1338 BT_DBG("Unable to find a pending command");
1339 return;
1340 }
1341
1342 pairing_complete(cmd, status);
1343}
1344
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001346{
1347 struct hci_dev *hdev;
1348 struct mgmt_cp_pair_device *cp;
1349 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001350 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001351 u8 sec_level, auth_type;
1352 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001353 int err;
1354
1355 BT_DBG("");
1356
1357 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001358
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001359 if (len != sizeof(*cp))
1360 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1361
Szymon Janc4e51eae2011-02-25 19:05:48 +01001362 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001363 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365
Andre Guedes8c156c32011-07-07 10:30:36 -03001366 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001367
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001368 sec_level = BT_SECURITY_MEDIUM;
1369 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001371 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001374 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1375 if (entry)
1376 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1377 auth_type);
1378 else
1379 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1380 auth_type);
1381
Ville Tervo30e76272011-02-22 16:10:53 -03001382 if (IS_ERR(conn)) {
1383 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384 goto unlock;
1385 }
1386
1387 if (conn->connect_cfm_cb) {
1388 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001390 goto unlock;
1391 }
1392
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001394 if (!cmd) {
1395 err = -ENOMEM;
1396 hci_conn_put(conn);
1397 goto unlock;
1398 }
1399
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001400 /* For LE, just connecting isn't a proof that the pairing finished */
1401 if (!entry)
1402 conn->connect_cfm_cb = pairing_complete_cb;
1403
Johan Hedberge9a416b2011-02-19 12:05:56 -03001404 conn->security_cfm_cb = pairing_complete_cb;
1405 conn->disconn_cfm_cb = pairing_complete_cb;
1406 conn->io_capability = cp->io_cap;
1407 cmd->user_data = conn;
1408
1409 if (conn->state == BT_CONNECTED &&
1410 hci_conn_security(conn, sec_level, auth_type))
1411 pairing_complete(cmd, 0);
1412
1413 err = 0;
1414
1415unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001416 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001417 hci_dev_put(hdev);
1418
1419 return err;
1420}
1421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1423 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001424{
1425 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001427 struct pending_cmd *cmd;
1428 struct hci_dev *hdev;
1429 int err;
1430
1431 BT_DBG("");
1432
Johan Hedberga5c29682011-02-19 12:05:57 -03001433 if (success) {
1434 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1435 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1436 } else {
1437 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1438 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1439 }
1440
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001441 if (len != sizeof(*cp))
1442 return cmd_status(sk, index, mgmt_op, EINVAL);
1443
Szymon Janc4e51eae2011-02-25 19:05:48 +01001444 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001445 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001447
Andre Guedes8c156c32011-07-07 10:30:36 -03001448 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001449
Johan Hedberga5c29682011-02-19 12:05:57 -03001450 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001452 goto failed;
1453 }
1454
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001456 if (!cmd) {
1457 err = -ENOMEM;
1458 goto failed;
1459 }
1460
1461 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001462 if (err < 0)
1463 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001464
1465failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001466 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001467 hci_dev_put(hdev);
1468
1469 return err;
1470}
1471
Johan Hedbergb312b1612011-03-16 14:29:37 +02001472static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1473 u16 len)
1474{
1475 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1476 struct hci_cp_write_local_name hci_cp;
1477 struct hci_dev *hdev;
1478 struct pending_cmd *cmd;
1479 int err;
1480
1481 BT_DBG("");
1482
1483 if (len != sizeof(*mgmt_cp))
1484 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1485
1486 hdev = hci_dev_get(index);
1487 if (!hdev)
1488 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1489
Andre Guedes8c156c32011-07-07 10:30:36 -03001490 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001491
1492 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1493 if (!cmd) {
1494 err = -ENOMEM;
1495 goto failed;
1496 }
1497
1498 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1499 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1500 &hci_cp);
1501 if (err < 0)
1502 mgmt_pending_remove(cmd);
1503
1504failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001505 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001506 hci_dev_put(hdev);
1507
1508 return err;
1509}
1510
Szymon Jancc35938b2011-03-22 13:12:21 +01001511static int read_local_oob_data(struct sock *sk, u16 index)
1512{
1513 struct hci_dev *hdev;
1514 struct pending_cmd *cmd;
1515 int err;
1516
1517 BT_DBG("hci%u", index);
1518
1519 hdev = hci_dev_get(index);
1520 if (!hdev)
1521 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1522 ENODEV);
1523
Andre Guedes8c156c32011-07-07 10:30:36 -03001524 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001525
1526 if (!test_bit(HCI_UP, &hdev->flags)) {
1527 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1528 ENETDOWN);
1529 goto unlock;
1530 }
1531
1532 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1533 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1534 EOPNOTSUPP);
1535 goto unlock;
1536 }
1537
1538 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1539 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1540 goto unlock;
1541 }
1542
1543 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1544 if (!cmd) {
1545 err = -ENOMEM;
1546 goto unlock;
1547 }
1548
1549 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1550 if (err < 0)
1551 mgmt_pending_remove(cmd);
1552
1553unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001554 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001555 hci_dev_put(hdev);
1556
1557 return err;
1558}
1559
Szymon Janc2763eda2011-03-22 13:12:22 +01001560static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1561 u16 len)
1562{
1563 struct hci_dev *hdev;
1564 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1565 int err;
1566
1567 BT_DBG("hci%u ", index);
1568
1569 if (len != sizeof(*cp))
1570 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1571 EINVAL);
1572
1573 hdev = hci_dev_get(index);
1574 if (!hdev)
1575 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1576 ENODEV);
1577
Andre Guedes8c156c32011-07-07 10:30:36 -03001578 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001579
1580 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1581 cp->randomizer);
1582 if (err < 0)
1583 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1584 else
1585 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1586 0);
1587
Andre Guedes8c156c32011-07-07 10:30:36 -03001588 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001589 hci_dev_put(hdev);
1590
1591 return err;
1592}
1593
1594static int remove_remote_oob_data(struct sock *sk, u16 index,
1595 unsigned char *data, u16 len)
1596{
1597 struct hci_dev *hdev;
1598 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1599 int err;
1600
1601 BT_DBG("hci%u ", index);
1602
1603 if (len != sizeof(*cp))
1604 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1605 EINVAL);
1606
1607 hdev = hci_dev_get(index);
1608 if (!hdev)
1609 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1610 ENODEV);
1611
Andre Guedes8c156c32011-07-07 10:30:36 -03001612 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001613
1614 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1615 if (err < 0)
1616 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1617 -err);
1618 else
1619 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1620 NULL, 0);
1621
Andre Guedes8c156c32011-07-07 10:30:36 -03001622 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001623 hci_dev_put(hdev);
1624
1625 return err;
1626}
1627
Johan Hedberg14a53662011-04-27 10:29:56 -04001628static int start_discovery(struct sock *sk, u16 index)
1629{
1630 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1631 struct hci_cp_inquiry cp;
1632 struct pending_cmd *cmd;
1633 struct hci_dev *hdev;
1634 int err;
1635
1636 BT_DBG("hci%u", index);
1637
1638 hdev = hci_dev_get(index);
1639 if (!hdev)
1640 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1641
1642 hci_dev_lock_bh(hdev);
1643
1644 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1645 if (!cmd) {
1646 err = -ENOMEM;
1647 goto failed;
1648 }
1649
1650 memset(&cp, 0, sizeof(cp));
1651 memcpy(&cp.lap, lap, 3);
1652 cp.length = 0x08;
1653 cp.num_rsp = 0x00;
1654
1655 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1656 if (err < 0)
1657 mgmt_pending_remove(cmd);
1658
1659failed:
1660 hci_dev_unlock_bh(hdev);
1661 hci_dev_put(hdev);
1662
1663 return err;
1664}
1665
1666static int stop_discovery(struct sock *sk, u16 index)
1667{
1668 struct hci_dev *hdev;
1669 struct pending_cmd *cmd;
1670 int err;
1671
1672 BT_DBG("hci%u", index);
1673
1674 hdev = hci_dev_get(index);
1675 if (!hdev)
1676 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1677
1678 hci_dev_lock_bh(hdev);
1679
1680 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1681 if (!cmd) {
1682 err = -ENOMEM;
1683 goto failed;
1684 }
1685
1686 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1687 if (err < 0)
1688 mgmt_pending_remove(cmd);
1689
1690failed:
1691 hci_dev_unlock_bh(hdev);
1692 hci_dev_put(hdev);
1693
1694 return err;
1695}
1696
Antti Julku7fbec222011-06-15 12:01:15 +03001697static int block_device(struct sock *sk, u16 index, unsigned char *data,
1698 u16 len)
1699{
1700 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001701 struct pending_cmd *cmd;
1702 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
1718 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1719 if (!cmd) {
1720 err = -ENOMEM;
1721 goto failed;
1722 }
1723
Antti Julku7fbec222011-06-15 12:01:15 +03001724 err = hci_blacklist_add(hdev, &cp->bdaddr);
1725
1726 if (err < 0)
1727 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1728 else
1729 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1730 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001731
1732 mgmt_pending_remove(cmd);
1733
1734failed:
1735 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001736 hci_dev_put(hdev);
1737
1738 return err;
1739}
1740
1741static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1742 u16 len)
1743{
1744 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001745 struct pending_cmd *cmd;
1746 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001747 int err;
1748
1749 BT_DBG("hci%u", index);
1750
Antti Julku7fbec222011-06-15 12:01:15 +03001751 if (len != sizeof(*cp))
1752 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1753 EINVAL);
1754
1755 hdev = hci_dev_get(index);
1756 if (!hdev)
1757 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1758 ENODEV);
1759
Antti Julku5e762442011-08-25 16:48:02 +03001760 hci_dev_lock_bh(hdev);
1761
1762 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1763 if (!cmd) {
1764 err = -ENOMEM;
1765 goto failed;
1766 }
1767
Antti Julku7fbec222011-06-15 12:01:15 +03001768 err = hci_blacklist_del(hdev, &cp->bdaddr);
1769
1770 if (err < 0)
1771 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1772 else
1773 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1774 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001775
1776 mgmt_pending_remove(cmd);
1777
1778failed:
1779 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001780 hci_dev_put(hdev);
1781
1782 return err;
1783}
1784
Antti Julkuf6422ec2011-06-22 13:11:56 +03001785static int set_fast_connectable(struct sock *sk, u16 index,
1786 unsigned char *data, u16 len)
1787{
1788 struct hci_dev *hdev;
1789 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1790 struct hci_cp_write_page_scan_activity acp;
1791 u8 type;
1792 int err;
1793
1794 BT_DBG("hci%u", index);
1795
1796 if (len != sizeof(*cp))
1797 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1798 EINVAL);
1799
1800 hdev = hci_dev_get(index);
1801 if (!hdev)
1802 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1803 ENODEV);
1804
1805 hci_dev_lock(hdev);
1806
1807 if (cp->enable) {
1808 type = PAGE_SCAN_TYPE_INTERLACED;
1809 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1810 } else {
1811 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1812 acp.interval = 0x0800; /* default 1.28 sec page scan */
1813 }
1814
1815 acp.window = 0x0012; /* default 11.25 msec page scan window */
1816
1817 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1818 sizeof(acp), &acp);
1819 if (err < 0) {
1820 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1821 -err);
1822 goto done;
1823 }
1824
1825 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1826 if (err < 0) {
1827 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1828 -err);
1829 goto done;
1830 }
1831
1832 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1833 NULL, 0);
1834done:
1835 hci_dev_unlock(hdev);
1836 hci_dev_put(hdev);
1837
1838 return err;
1839}
1840
Johan Hedberg03811012010-12-08 00:21:06 +02001841int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1842{
1843 unsigned char *buf;
1844 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001846 int err;
1847
1848 BT_DBG("got %zu bytes", msglen);
1849
1850 if (msglen < sizeof(*hdr))
1851 return -EINVAL;
1852
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001853 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001854 if (!buf)
1855 return -ENOMEM;
1856
1857 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1858 err = -EFAULT;
1859 goto done;
1860 }
1861
1862 hdr = (struct mgmt_hdr *) buf;
1863 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001865 len = get_unaligned_le16(&hdr->len);
1866
1867 if (len != msglen - sizeof(*hdr)) {
1868 err = -EINVAL;
1869 goto done;
1870 }
1871
1872 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001873 case MGMT_OP_READ_VERSION:
1874 err = read_version(sk);
1875 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001876 case MGMT_OP_READ_INDEX_LIST:
1877 err = read_index_list(sk);
1878 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001879 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001881 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001882 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001884 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001885 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001887 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001888 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001890 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001891 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001893 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001894 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001896 break;
1897 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001899 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001900 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001902 break;
1903 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001905 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001908 break;
1909 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001911 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001912 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001914 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001915 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001916 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001917 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001918 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001919 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001920 break;
1921 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001922 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001923 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001924 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001925 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001926 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001927 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001928 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001929 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001930 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001931 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001932 break;
1933 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001934 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001935 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001936 case MGMT_OP_SET_LOCAL_NAME:
1937 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1938 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001939 case MGMT_OP_READ_LOCAL_OOB_DATA:
1940 err = read_local_oob_data(sk, index);
1941 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001942 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1943 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1944 break;
1945 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1946 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1947 len);
1948 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001949 case MGMT_OP_START_DISCOVERY:
1950 err = start_discovery(sk, index);
1951 break;
1952 case MGMT_OP_STOP_DISCOVERY:
1953 err = stop_discovery(sk, index);
1954 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001955 case MGMT_OP_BLOCK_DEVICE:
1956 err = block_device(sk, index, buf + sizeof(*hdr), len);
1957 break;
1958 case MGMT_OP_UNBLOCK_DEVICE:
1959 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1960 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001961 case MGMT_OP_SET_FAST_CONNECTABLE:
1962 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1963 len);
1964 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001965 default:
1966 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001967 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001968 break;
1969 }
1970
Johan Hedberge41d8b42010-12-13 21:07:03 +02001971 if (err < 0)
1972 goto done;
1973
Johan Hedberg03811012010-12-08 00:21:06 +02001974 err = msglen;
1975
1976done:
1977 kfree(buf);
1978 return err;
1979}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001980
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001981int mgmt_index_added(u16 index)
1982{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001983 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001984}
1985
1986int mgmt_index_removed(u16 index)
1987{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001988 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001989}
1990
Johan Hedberg73f22f62010-12-29 16:00:25 +02001991struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001992 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001993 struct sock *sk;
1994};
1995
Johan Hedberg72a734e2010-12-30 00:38:22 +02001996static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001997{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001998 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001999 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000
Johan Hedberg72a734e2010-12-30 00:38:22 +02002001 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002002 return;
2003
Johan Hedberg053f0212011-01-26 13:07:10 +02002004 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005
2006 list_del(&cmd->list);
2007
2008 if (match->sk == NULL) {
2009 match->sk = cmd->sk;
2010 sock_hold(match->sk);
2011 }
2012
2013 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002014}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002015
2016int mgmt_powered(u16 index, u8 powered)
2017{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002018 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002020 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002021
Johan Hedberg72a734e2010-12-30 00:38:22 +02002022 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002023
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002025
Szymon Janc4e51eae2011-02-25 19:05:48 +01002026 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002027
2028 if (match.sk)
2029 sock_put(match.sk);
2030
2031 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002032}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002033
Johan Hedberg73f22f62010-12-29 16:00:25 +02002034int mgmt_discoverable(u16 index, u8 discoverable)
2035{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002037 struct cmd_lookup match = { discoverable, NULL };
2038 int ret;
2039
Szymon Jancb8534e02011-03-01 16:55:34 +01002040 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041
Johan Hedberg72a734e2010-12-30 00:38:22 +02002042 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002043
Szymon Janc4e51eae2011-02-25 19:05:48 +01002044 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2045 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002046
2047 if (match.sk)
2048 sock_put(match.sk);
2049
2050 return ret;
2051}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002053int mgmt_connectable(u16 index, u8 connectable)
2054{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002055 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002056 struct cmd_lookup match = { connectable, NULL };
2057 int ret;
2058
Johan Hedberg72a734e2010-12-30 00:38:22 +02002059 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002060
Johan Hedberg72a734e2010-12-30 00:38:22 +02002061 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002062
Szymon Janc4e51eae2011-02-25 19:05:48 +01002063 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002064
2065 if (match.sk)
2066 sock_put(match.sk);
2067
2068 return ret;
2069}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002070
Johan Hedberg4df378a2011-04-28 11:29:03 -07002071int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002072{
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -03002073 struct mgmt_ev_new_key *ev;
2074 int err, total;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002075
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -03002076 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2077 ev = kzalloc(total, GFP_ATOMIC);
2078 if (!ev)
2079 return -ENOMEM;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002080
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -03002081 bacpy(&ev->key.bdaddr, &key->bdaddr);
2082 ev->key.type = key->type;
2083 memcpy(ev->key.val, key->val, 16);
2084 ev->key.pin_len = key->pin_len;
2085 ev->key.dlen = key->dlen;
2086 ev->store_hint = persistent;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002087
Vinicius Costa Gomes5a0a8b42011-07-08 18:31:44 -03002088 memcpy(ev->key.data, key->data, key->dlen);
2089
2090 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2091
2092 kfree(ev);
2093
2094 return err;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002095}
Johan Hedbergf7520542011-01-20 12:34:39 +02002096
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002097int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002098{
2099 struct mgmt_ev_connected ev;
2100
Johan Hedbergf7520542011-01-20 12:34:39 +02002101 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002102 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002103
Szymon Janc4e51eae2011-02-25 19:05:48 +01002104 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002105}
2106
Johan Hedberg8962ee72011-01-20 12:40:27 +02002107static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2108{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002109 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002110 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002111 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002112
Johan Hedberga38528f2011-01-22 06:46:43 +02002113 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002114
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002116
2117 *sk = cmd->sk;
2118 sock_hold(*sk);
2119
Johan Hedberga664b5b2011-02-19 12:06:02 -03002120 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002121}
2122
Johan Hedbergf7520542011-01-20 12:34:39 +02002123int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2124{
2125 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002126 struct sock *sk = NULL;
2127 int err;
2128
2129 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002130
Johan Hedbergf7520542011-01-20 12:34:39 +02002131 bacpy(&ev.bdaddr, bdaddr);
2132
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
2157int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2158{
2159 struct mgmt_ev_connect_failed ev;
2160
Johan Hedberg17d5c042011-01-22 06:09:08 +02002161 bacpy(&ev.bdaddr, bdaddr);
2162 ev.status = status;
2163
Szymon Janc4e51eae2011-02-25 19:05:48 +01002164 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002165}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002166
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002167int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002168{
2169 struct mgmt_ev_pin_code_request ev;
2170
Johan Hedberg980e1a52011-01-22 06:10:07 +02002171 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002172 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002173
Szymon Janc4e51eae2011-02-25 19:05:48 +01002174 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2175 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176}
2177
2178int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2179{
2180 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002181 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182 int err;
2183
2184 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2185 if (!cmd)
2186 return -ENOENT;
2187
Johan Hedbergac56fb12011-02-19 12:05:59 -03002188 bacpy(&rp.bdaddr, bdaddr);
2189 rp.status = status;
2190
Szymon Janc4e51eae2011-02-25 19:05:48 +01002191 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2192 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002193
Johan Hedberga664b5b2011-02-19 12:06:02 -03002194 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002195
2196 return err;
2197}
2198
2199int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2200{
2201 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002202 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002203 int err;
2204
2205 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2206 if (!cmd)
2207 return -ENOENT;
2208
Johan Hedbergac56fb12011-02-19 12:05:59 -03002209 bacpy(&rp.bdaddr, bdaddr);
2210 rp.status = status;
2211
Szymon Janc4e51eae2011-02-25 19:05:48 +01002212 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2213 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002214
Johan Hedberga664b5b2011-02-19 12:06:02 -03002215 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216
2217 return err;
2218}
Johan Hedberga5c29682011-02-19 12:05:57 -03002219
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002220int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2221 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002222{
2223 struct mgmt_ev_user_confirm_request ev;
2224
2225 BT_DBG("hci%u", index);
2226
Johan Hedberga5c29682011-02-19 12:05:57 -03002227 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002228 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002229 put_unaligned_le32(value, &ev.value);
2230
Szymon Janc4e51eae2011-02-25 19:05:48 +01002231 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2232 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002233}
2234
2235static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2236 u8 opcode)
2237{
2238 struct pending_cmd *cmd;
2239 struct mgmt_rp_user_confirm_reply rp;
2240 int err;
2241
2242 cmd = mgmt_pending_find(opcode, index);
2243 if (!cmd)
2244 return -ENOENT;
2245
Johan Hedberga5c29682011-02-19 12:05:57 -03002246 bacpy(&rp.bdaddr, bdaddr);
2247 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002248 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002249
Johan Hedberga664b5b2011-02-19 12:06:02 -03002250 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002251
2252 return err;
2253}
2254
2255int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2256{
2257 return confirm_reply_complete(index, bdaddr, status,
2258 MGMT_OP_USER_CONFIRM_REPLY);
2259}
2260
Szymon Jancb8534e02011-03-01 16:55:34 +01002261int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002262{
2263 return confirm_reply_complete(index, bdaddr, status,
2264 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2265}
Johan Hedberg2a611692011-02-19 12:06:00 -03002266
2267int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2268{
2269 struct mgmt_ev_auth_failed ev;
2270
Johan Hedberg2a611692011-02-19 12:06:00 -03002271 bacpy(&ev.bdaddr, bdaddr);
2272 ev.status = status;
2273
Szymon Janc4e51eae2011-02-25 19:05:48 +01002274 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002275}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002276
2277int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2278{
2279 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002280 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002281 struct mgmt_cp_set_local_name ev;
2282 int err;
2283
2284 memset(&ev, 0, sizeof(ev));
2285 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2286
2287 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2288 if (!cmd)
2289 goto send_event;
2290
2291 if (status) {
2292 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2293 goto failed;
2294 }
2295
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002296 hdev = hci_dev_get(index);
2297 if (hdev) {
2298 hci_dev_lock_bh(hdev);
2299 update_eir(hdev);
2300 hci_dev_unlock_bh(hdev);
2301 hci_dev_put(hdev);
2302 }
2303
Johan Hedbergb312b1612011-03-16 14:29:37 +02002304 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2305 sizeof(ev));
2306 if (err < 0)
2307 goto failed;
2308
2309send_event:
2310 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2311 cmd ? cmd->sk : NULL);
2312
2313failed:
2314 if (cmd)
2315 mgmt_pending_remove(cmd);
2316 return err;
2317}
Szymon Jancc35938b2011-03-22 13:12:21 +01002318
2319int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2320 u8 status)
2321{
2322 struct pending_cmd *cmd;
2323 int err;
2324
2325 BT_DBG("hci%u status %u", index, status);
2326
2327 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2328 if (!cmd)
2329 return -ENOENT;
2330
2331 if (status) {
2332 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2333 EIO);
2334 } else {
2335 struct mgmt_rp_read_local_oob_data rp;
2336
2337 memcpy(rp.hash, hash, sizeof(rp.hash));
2338 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2339
2340 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2341 &rp, sizeof(rp));
2342 }
2343
2344 mgmt_pending_remove(cmd);
2345
2346 return err;
2347}
Johan Hedberge17acd42011-03-30 23:57:16 +03002348
2349int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2350 u8 *eir)
2351{
2352 struct mgmt_ev_device_found ev;
2353
2354 memset(&ev, 0, sizeof(ev));
2355
2356 bacpy(&ev.bdaddr, bdaddr);
2357 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2358 ev.rssi = rssi;
2359
2360 if (eir)
2361 memcpy(ev.eir, eir, sizeof(ev.eir));
2362
2363 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2364}
Johan Hedberga88a9652011-03-30 13:18:12 +03002365
2366int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2367{
2368 struct mgmt_ev_remote_name ev;
2369
2370 memset(&ev, 0, sizeof(ev));
2371
2372 bacpy(&ev.bdaddr, bdaddr);
2373 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2374
2375 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2376}
Johan Hedberg314b2382011-04-27 10:29:57 -04002377
2378int mgmt_discovering(u16 index, u8 discovering)
2379{
2380 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2381 sizeof(discovering), NULL);
2382}
Antti Julku5e762442011-08-25 16:48:02 +03002383
2384int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2385{
2386 struct pending_cmd *cmd;
2387 struct mgmt_ev_device_blocked ev;
2388
2389 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2390
2391 bacpy(&ev.bdaddr, bdaddr);
2392
2393 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2394 cmd ? cmd->sk : NULL);
2395}
2396
2397int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2398{
2399 struct pending_cmd *cmd;
2400 struct mgmt_ev_device_unblocked ev;
2401
2402 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2403
2404 bacpy(&ev.bdaddr, bdaddr);
2405
2406 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2407 cmd ? cmd->sk : NULL);
2408}