blob: dae382ce70201d5f4adbacde509c665c467d95ac [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
44LIST_HEAD(cmd_list);
45
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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300182 hci_dev_lock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300211 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300319 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300346 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300371 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300406 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300432 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300466 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300525 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300541 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300742 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300766 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300791 hci_dev_lock(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:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300826 hci_dev_unlock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300850 hci_dev_lock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300860 hci_dev_unlock(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 Jancb8534e0f2011-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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300882 hci_dev_lock(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
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300900 hci_dev_unlock(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 Hedberg55ed8ca2011-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;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200911 int i;
912
913 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100914
915 if (len < sizeof(*cp))
916 return -EINVAL;
917
Johan Hedberg55ed8ca2011-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);
921 if (expected_len != len) {
922 BT_ERR("load_keys: expected %u bytes, got %u bytes",
923 len, expected_len);
924 return -EINVAL;
925 }
926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200932 key_count);
933
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300934 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-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
945 for (i = 0; i < key_count; i++) {
946 struct mgmt_key_info *key = &cp->keys[i];
947
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700948 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200949 key->pin_len);
950 }
951
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300952 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200953 hci_dev_put(hdev);
954
955 return 0;
956}
957
Szymon Janc4e51eae2011-02-25 19:05:48 +0100958static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200959{
960 struct hci_dev *hdev;
961 struct mgmt_cp_remove_key *cp;
962 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200963 int err;
964
965 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200966
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100967 if (len != sizeof(*cp))
968 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
969
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200971 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100972 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200973
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300974 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200975
976 err = hci_remove_link_key(hdev, &cp->bdaddr);
977 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200979 goto unlock;
980 }
981
982 err = 0;
983
984 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
985 goto unlock;
986
987 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
988 if (conn) {
989 struct hci_cp_disconnect dc;
990
991 put_unaligned_le16(conn->handle, &dc.handle);
992 dc.reason = 0x13; /* Remote User Terminated Connection */
993 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
994 }
995
996unlock:
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300997 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200998 hci_dev_put(hdev);
999
1000 return err;
1001}
1002
Szymon Janc4e51eae2011-02-25 19:05:48 +01001003static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001004{
1005 struct hci_dev *hdev;
1006 struct mgmt_cp_disconnect *cp;
1007 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001008 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001009 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001010 int err;
1011
1012 BT_DBG("");
1013
1014 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001015
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001016 if (len != sizeof(*cp))
1017 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1018
Szymon Janc4e51eae2011-02-25 19:05:48 +01001019 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001022
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001023 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001024
1025 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001026 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001027 goto failed;
1028 }
1029
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1031 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032 goto failed;
1033 }
1034
1035 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001036 if (!conn)
1037 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1038
Johan Hedberg8962ee72011-01-20 12:40:27 +02001039 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001040 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001041 goto failed;
1042 }
1043
Szymon Janc4e51eae2011-02-25 19:05:48 +01001044 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001045 if (!cmd) {
1046 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001047 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001048 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049
1050 put_unaligned_le16(conn->handle, &dc.handle);
1051 dc.reason = 0x13; /* Remote User Terminated Connection */
1052
1053 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1054 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001055 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001056
1057failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001058 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059 hci_dev_put(hdev);
1060
1061 return err;
1062}
1063
Szymon Janc8ce62842011-03-01 16:55:32 +01001064static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001065{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001066 struct mgmt_rp_get_connections *rp;
1067 struct hci_dev *hdev;
1068 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001069 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001071 int i, err;
1072
1073 BT_DBG("");
1074
Szymon Janc4e51eae2011-02-25 19:05:48 +01001075 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001076 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001077 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001078
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001079 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001080
1081 count = 0;
1082 list_for_each(p, &hdev->conn_hash.list) {
1083 count++;
1084 }
1085
Johan Hedberga38528f2011-01-22 06:46:43 +02001086 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1087 rp = kmalloc(rp_len, GFP_ATOMIC);
1088 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001089 err = -ENOMEM;
1090 goto unlock;
1091 }
1092
Johan Hedberg2784eb42011-01-21 13:56:35 +02001093 put_unaligned_le16(count, &rp->conn_count);
1094
1095 read_lock(&hci_dev_list_lock);
1096
1097 i = 0;
1098 list_for_each(p, &hdev->conn_hash.list) {
1099 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1100
1101 bacpy(&rp->conn[i++], &c->dst);
1102 }
1103
1104 read_unlock(&hci_dev_list_lock);
1105
Szymon Janc4e51eae2011-02-25 19:05:48 +01001106 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107
1108unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001109 kfree(rp);
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001110 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001111 hci_dev_put(hdev);
1112 return err;
1113}
1114
Szymon Janc4e51eae2011-02-25 19:05:48 +01001115static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1116 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001117{
1118 struct hci_dev *hdev;
1119 struct mgmt_cp_pin_code_reply *cp;
1120 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001121 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001122 int err;
1123
1124 BT_DBG("");
1125
1126 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001127
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001128 if (len != sizeof(*cp))
1129 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001132 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001133 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001134
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001135 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136
1137 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001138 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001139 goto failed;
1140 }
1141
Szymon Janc4e51eae2011-02-25 19:05:48 +01001142 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001143 if (!cmd) {
1144 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001146 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001147
1148 bacpy(&reply.bdaddr, &cp->bdaddr);
1149 reply.pin_len = cp->pin_len;
1150 memcpy(reply.pin_code, cp->pin_code, 16);
1151
1152 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1153 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001154 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001155
1156failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001157 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001158 hci_dev_put(hdev);
1159
1160 return err;
1161}
1162
Szymon Janc4e51eae2011-02-25 19:05:48 +01001163static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1164 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001165{
1166 struct hci_dev *hdev;
1167 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001168 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001169 int err;
1170
1171 BT_DBG("");
1172
1173 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001174
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001175 if (len != sizeof(*cp))
1176 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1177 EINVAL);
1178
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001180 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1182 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001183
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001184 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185
1186 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001187 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1188 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189 goto failed;
1190 }
1191
Szymon Janc4e51eae2011-02-25 19:05:48 +01001192 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001193 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001194 if (!cmd) {
1195 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001196 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001197 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198
Szymon Janc3cf2a4f2011-03-01 16:55:33 +01001199 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200 &cp->bdaddr);
1201 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001202 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203
1204failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001205 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001206 hci_dev_put(hdev);
1207
1208 return err;
1209}
1210
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1212 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001213{
1214 struct hci_dev *hdev;
1215 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001216
1217 BT_DBG("");
1218
1219 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001220
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001221 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001222 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001223
Szymon Janc4e51eae2011-02-25 19:05:48 +01001224 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001225 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001226 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001227
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001228 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001229
1230 hdev->io_capability = cp->io_capability;
1231
1232 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001233 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001234
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001235 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001236 hci_dev_put(hdev);
1237
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001239}
1240
Johan Hedberge9a416b2011-02-19 12:05:56 -03001241static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1242{
1243 struct hci_dev *hdev = conn->hdev;
1244 struct list_head *p;
1245
1246 list_for_each(p, &cmd_list) {
1247 struct pending_cmd *cmd;
1248
1249 cmd = list_entry(p, struct pending_cmd, list);
1250
1251 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1252 continue;
1253
1254 if (cmd->index != hdev->id)
1255 continue;
1256
1257 if (cmd->user_data != conn)
1258 continue;
1259
1260 return cmd;
1261 }
1262
1263 return NULL;
1264}
1265
1266static void pairing_complete(struct pending_cmd *cmd, u8 status)
1267{
1268 struct mgmt_rp_pair_device rp;
1269 struct hci_conn *conn = cmd->user_data;
1270
Johan Hedberge9a416b2011-02-19 12:05:56 -03001271 bacpy(&rp.bdaddr, &conn->dst);
1272 rp.status = status;
1273
Szymon Janc4e51eae2011-02-25 19:05:48 +01001274 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001275
1276 /* So we don't get further callbacks for this connection */
1277 conn->connect_cfm_cb = NULL;
1278 conn->security_cfm_cb = NULL;
1279 conn->disconn_cfm_cb = NULL;
1280
1281 hci_conn_put(conn);
1282
Johan Hedberga664b5b2011-02-19 12:06:02 -03001283 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001284}
1285
1286static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1287{
1288 struct pending_cmd *cmd;
1289
1290 BT_DBG("status %u", status);
1291
1292 cmd = find_pairing(conn);
1293 if (!cmd) {
1294 BT_DBG("Unable to find a pending command");
1295 return;
1296 }
1297
1298 pairing_complete(cmd, status);
1299}
1300
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001302{
1303 struct hci_dev *hdev;
1304 struct mgmt_cp_pair_device *cp;
1305 struct pending_cmd *cmd;
1306 u8 sec_level, auth_type;
1307 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001308 int err;
1309
1310 BT_DBG("");
1311
1312 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001313
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001314 if (len != sizeof(*cp))
1315 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001318 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001320
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001321 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322
1323 if (cp->io_cap == 0x03) {
1324 sec_level = BT_SECURITY_MEDIUM;
1325 auth_type = HCI_AT_DEDICATED_BONDING;
1326 } else {
1327 sec_level = BT_SECURITY_HIGH;
1328 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1329 }
1330
1331 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001332 if (IS_ERR(conn)) {
1333 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001334 goto unlock;
1335 }
1336
1337 if (conn->connect_cfm_cb) {
1338 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340 goto unlock;
1341 }
1342
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001344 if (!cmd) {
1345 err = -ENOMEM;
1346 hci_conn_put(conn);
1347 goto unlock;
1348 }
1349
1350 conn->connect_cfm_cb = pairing_complete_cb;
1351 conn->security_cfm_cb = pairing_complete_cb;
1352 conn->disconn_cfm_cb = pairing_complete_cb;
1353 conn->io_capability = cp->io_cap;
1354 cmd->user_data = conn;
1355
1356 if (conn->state == BT_CONNECTED &&
1357 hci_conn_security(conn, sec_level, auth_type))
1358 pairing_complete(cmd, 0);
1359
1360 err = 0;
1361
1362unlock:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001363 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001364 hci_dev_put(hdev);
1365
1366 return err;
1367}
1368
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1370 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001371{
1372 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001373 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001374 struct pending_cmd *cmd;
1375 struct hci_dev *hdev;
1376 int err;
1377
1378 BT_DBG("");
1379
Johan Hedberga5c29682011-02-19 12:05:57 -03001380 if (success) {
1381 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1382 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1383 } else {
1384 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1385 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1386 }
1387
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001388 if (len != sizeof(*cp))
1389 return cmd_status(sk, index, mgmt_op, EINVAL);
1390
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001392 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001394
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001395 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001396
Johan Hedberga5c29682011-02-19 12:05:57 -03001397 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001399 goto failed;
1400 }
1401
Szymon Janc4e51eae2011-02-25 19:05:48 +01001402 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001403 if (!cmd) {
1404 err = -ENOMEM;
1405 goto failed;
1406 }
1407
1408 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001409 if (err < 0)
1410 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001411
1412failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001413 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001414 hci_dev_put(hdev);
1415
1416 return err;
1417}
1418
Johan Hedbergb312b1612011-03-16 14:29:37 +02001419static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1420 u16 len)
1421{
1422 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1423 struct hci_cp_write_local_name hci_cp;
1424 struct hci_dev *hdev;
1425 struct pending_cmd *cmd;
1426 int err;
1427
1428 BT_DBG("");
1429
1430 if (len != sizeof(*mgmt_cp))
1431 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1432
1433 hdev = hci_dev_get(index);
1434 if (!hdev)
1435 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1436
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001437 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001438
1439 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1440 if (!cmd) {
1441 err = -ENOMEM;
1442 goto failed;
1443 }
1444
1445 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1446 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1447 &hci_cp);
1448 if (err < 0)
1449 mgmt_pending_remove(cmd);
1450
1451failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001452 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001453 hci_dev_put(hdev);
1454
1455 return err;
1456}
1457
Szymon Jancc35938b2011-03-22 13:12:21 +01001458static int read_local_oob_data(struct sock *sk, u16 index)
1459{
1460 struct hci_dev *hdev;
1461 struct pending_cmd *cmd;
1462 int err;
1463
1464 BT_DBG("hci%u", index);
1465
1466 hdev = hci_dev_get(index);
1467 if (!hdev)
1468 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1469 ENODEV);
1470
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001471 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001472
1473 if (!test_bit(HCI_UP, &hdev->flags)) {
1474 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1475 ENETDOWN);
1476 goto unlock;
1477 }
1478
1479 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1480 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1481 EOPNOTSUPP);
1482 goto unlock;
1483 }
1484
1485 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1486 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1487 goto unlock;
1488 }
1489
1490 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1491 if (!cmd) {
1492 err = -ENOMEM;
1493 goto unlock;
1494 }
1495
1496 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1497 if (err < 0)
1498 mgmt_pending_remove(cmd);
1499
1500unlock:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001501 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001502 hci_dev_put(hdev);
1503
1504 return err;
1505}
1506
Szymon Janc2763eda2011-03-22 13:12:22 +01001507static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1508 u16 len)
1509{
1510 struct hci_dev *hdev;
1511 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1512 int err;
1513
1514 BT_DBG("hci%u ", index);
1515
1516 if (len != sizeof(*cp))
1517 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1518 EINVAL);
1519
1520 hdev = hci_dev_get(index);
1521 if (!hdev)
1522 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1523 ENODEV);
1524
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001525 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001526
1527 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1528 cp->randomizer);
1529 if (err < 0)
1530 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1531 else
1532 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1533 0);
1534
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001535 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001536 hci_dev_put(hdev);
1537
1538 return err;
1539}
1540
1541static int remove_remote_oob_data(struct sock *sk, u16 index,
1542 unsigned char *data, u16 len)
1543{
1544 struct hci_dev *hdev;
1545 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1546 int err;
1547
1548 BT_DBG("hci%u ", index);
1549
1550 if (len != sizeof(*cp))
1551 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1552 EINVAL);
1553
1554 hdev = hci_dev_get(index);
1555 if (!hdev)
1556 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1557 ENODEV);
1558
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001559 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001560
1561 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1562 if (err < 0)
1563 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1564 -err);
1565 else
1566 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1567 NULL, 0);
1568
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001569 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001570 hci_dev_put(hdev);
1571
1572 return err;
1573}
1574
Johan Hedberg14a53662011-04-27 10:29:56 -04001575static int start_discovery(struct sock *sk, u16 index)
1576{
1577 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1578 struct hci_cp_inquiry cp;
1579 struct pending_cmd *cmd;
1580 struct hci_dev *hdev;
1581 int err;
1582
1583 BT_DBG("hci%u", index);
1584
1585 hdev = hci_dev_get(index);
1586 if (!hdev)
1587 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1588
1589 hci_dev_lock_bh(hdev);
1590
1591 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1592 if (!cmd) {
1593 err = -ENOMEM;
1594 goto failed;
1595 }
1596
1597 memset(&cp, 0, sizeof(cp));
1598 memcpy(&cp.lap, lap, 3);
1599 cp.length = 0x08;
1600 cp.num_rsp = 0x00;
1601
1602 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1603 if (err < 0)
1604 mgmt_pending_remove(cmd);
1605
1606failed:
1607 hci_dev_unlock_bh(hdev);
1608 hci_dev_put(hdev);
1609
1610 return err;
1611}
1612
1613static int stop_discovery(struct sock *sk, u16 index)
1614{
1615 struct hci_dev *hdev;
1616 struct pending_cmd *cmd;
1617 int err;
1618
1619 BT_DBG("hci%u", index);
1620
1621 hdev = hci_dev_get(index);
1622 if (!hdev)
1623 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1624
1625 hci_dev_lock_bh(hdev);
1626
1627 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1628 if (!cmd) {
1629 err = -ENOMEM;
1630 goto failed;
1631 }
1632
1633 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1634 if (err < 0)
1635 mgmt_pending_remove(cmd);
1636
1637failed:
1638 hci_dev_unlock_bh(hdev);
1639 hci_dev_put(hdev);
1640
1641 return err;
1642}
1643
Johan Hedberg03811012010-12-08 00:21:06 +02001644int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1645{
1646 unsigned char *buf;
1647 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001648 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001649 int err;
1650
1651 BT_DBG("got %zu bytes", msglen);
1652
1653 if (msglen < sizeof(*hdr))
1654 return -EINVAL;
1655
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001656 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001657 if (!buf)
1658 return -ENOMEM;
1659
1660 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1661 err = -EFAULT;
1662 goto done;
1663 }
1664
1665 hdr = (struct mgmt_hdr *) buf;
1666 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001667 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001668 len = get_unaligned_le16(&hdr->len);
1669
1670 if (len != msglen - sizeof(*hdr)) {
1671 err = -EINVAL;
1672 goto done;
1673 }
1674
1675 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001676 case MGMT_OP_READ_VERSION:
1677 err = read_version(sk);
1678 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001679 case MGMT_OP_READ_INDEX_LIST:
1680 err = read_index_list(sk);
1681 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001682 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001683 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001684 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001685 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001686 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001687 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001688 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001689 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001690 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001691 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001692 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001693 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001694 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001695 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001696 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001697 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001698 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001699 break;
1700 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001701 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001702 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001703 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001704 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001705 break;
1706 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001707 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001708 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001709 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001710 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001711 break;
1712 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001713 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001714 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001715 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001716 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001717 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001718 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001719 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001720 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001721 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001722 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723 break;
1724 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001725 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001727 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001728 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001729 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001730 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001731 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001732 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001733 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001734 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001735 break;
1736 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001737 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001738 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001739 case MGMT_OP_SET_LOCAL_NAME:
1740 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1741 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001742 case MGMT_OP_READ_LOCAL_OOB_DATA:
1743 err = read_local_oob_data(sk, index);
1744 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001745 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1746 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1747 break;
1748 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1749 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1750 len);
1751 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001752 case MGMT_OP_START_DISCOVERY:
1753 err = start_discovery(sk, index);
1754 break;
1755 case MGMT_OP_STOP_DISCOVERY:
1756 err = stop_discovery(sk, index);
1757 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001758 default:
1759 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001760 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001761 break;
1762 }
1763
Johan Hedberge41d8b42010-12-13 21:07:03 +02001764 if (err < 0)
1765 goto done;
1766
Johan Hedberg03811012010-12-08 00:21:06 +02001767 err = msglen;
1768
1769done:
1770 kfree(buf);
1771 return err;
1772}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001773
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001774int mgmt_index_added(u16 index)
1775{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001776 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001777}
1778
1779int mgmt_index_removed(u16 index)
1780{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001781 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001782}
1783
Johan Hedberg73f22f62010-12-29 16:00:25 +02001784struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001785 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001786 struct sock *sk;
1787};
1788
Johan Hedberg72a734e2010-12-30 00:38:22 +02001789static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001790{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001791 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001792 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001793
Johan Hedberg72a734e2010-12-30 00:38:22 +02001794 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001795 return;
1796
Johan Hedberg053f0212011-01-26 13:07:10 +02001797 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001798
1799 list_del(&cmd->list);
1800
1801 if (match->sk == NULL) {
1802 match->sk = cmd->sk;
1803 sock_hold(match->sk);
1804 }
1805
1806 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001807}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001808
1809int mgmt_powered(u16 index, u8 powered)
1810{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001811 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001812 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001813 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001814
Johan Hedberg72a734e2010-12-30 00:38:22 +02001815 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001816
Johan Hedberg72a734e2010-12-30 00:38:22 +02001817 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001818
Szymon Janc4e51eae2011-02-25 19:05:48 +01001819 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001820
1821 if (match.sk)
1822 sock_put(match.sk);
1823
1824 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001825}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001826
Johan Hedberg73f22f62010-12-29 16:00:25 +02001827int mgmt_discoverable(u16 index, u8 discoverable)
1828{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001829 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001830 struct cmd_lookup match = { discoverable, NULL };
1831 int ret;
1832
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001833 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001834
Johan Hedberg72a734e2010-12-30 00:38:22 +02001835 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001836
Szymon Janc4e51eae2011-02-25 19:05:48 +01001837 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1838 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001839
1840 if (match.sk)
1841 sock_put(match.sk);
1842
1843 return ret;
1844}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001845
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001846int mgmt_connectable(u16 index, u8 connectable)
1847{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001848 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001849 struct cmd_lookup match = { connectable, NULL };
1850 int ret;
1851
Johan Hedberg72a734e2010-12-30 00:38:22 +02001852 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001853
Johan Hedberg72a734e2010-12-30 00:38:22 +02001854 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001855
Szymon Janc4e51eae2011-02-25 19:05:48 +01001856 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001857
1858 if (match.sk)
1859 sock_put(match.sk);
1860
1861 return ret;
1862}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001863
Johan Hedberg4df378a2011-04-28 11:29:03 -07001864int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001865{
1866 struct mgmt_ev_new_key ev;
1867
1868 memset(&ev, 0, sizeof(ev));
1869
Johan Hedberg4df378a2011-04-28 11:29:03 -07001870 ev.store_hint = persistent;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001871 bacpy(&ev.key.bdaddr, &key->bdaddr);
1872 ev.key.type = key->type;
1873 memcpy(ev.key.val, key->val, 16);
1874 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001875
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001877}
Johan Hedbergf7520542011-01-20 12:34:39 +02001878
1879int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1880{
1881 struct mgmt_ev_connected ev;
1882
Johan Hedbergf7520542011-01-20 12:34:39 +02001883 bacpy(&ev.bdaddr, bdaddr);
1884
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001886}
1887
Johan Hedberg8962ee72011-01-20 12:40:27 +02001888static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1889{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001890 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001891 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001892 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001893
Johan Hedberga38528f2011-01-22 06:46:43 +02001894 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001895
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001897
1898 *sk = cmd->sk;
1899 sock_hold(*sk);
1900
Johan Hedberga664b5b2011-02-19 12:06:02 -03001901 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001902}
1903
Johan Hedbergf7520542011-01-20 12:34:39 +02001904int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1905{
1906 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001907 struct sock *sk = NULL;
1908 int err;
1909
1910 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001911
Johan Hedbergf7520542011-01-20 12:34:39 +02001912 bacpy(&ev.bdaddr, bdaddr);
1913
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001915
1916 if (sk)
1917 sock_put(sk);
1918
1919 return err;
1920}
1921
1922int mgmt_disconnect_failed(u16 index)
1923{
1924 struct pending_cmd *cmd;
1925 int err;
1926
1927 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1928 if (!cmd)
1929 return -ENOENT;
1930
Szymon Janc4e51eae2011-02-25 19:05:48 +01001931 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001932
Johan Hedberga664b5b2011-02-19 12:06:02 -03001933 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001934
1935 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001936}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001937
1938int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1939{
1940 struct mgmt_ev_connect_failed ev;
1941
Johan Hedberg17d5c042011-01-22 06:09:08 +02001942 bacpy(&ev.bdaddr, bdaddr);
1943 ev.status = status;
1944
Szymon Janc4e51eae2011-02-25 19:05:48 +01001945 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001946}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001947
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02001948int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001949{
1950 struct mgmt_ev_pin_code_request ev;
1951
Johan Hedberg980e1a52011-01-22 06:10:07 +02001952 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02001953 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001954
Szymon Janc4e51eae2011-02-25 19:05:48 +01001955 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1956 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001957}
1958
1959int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1960{
1961 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001962 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001963 int err;
1964
1965 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1966 if (!cmd)
1967 return -ENOENT;
1968
Johan Hedbergac56fb12011-02-19 12:05:59 -03001969 bacpy(&rp.bdaddr, bdaddr);
1970 rp.status = status;
1971
Szymon Janc4e51eae2011-02-25 19:05:48 +01001972 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1973 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001974
Johan Hedberga664b5b2011-02-19 12:06:02 -03001975 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001976
1977 return err;
1978}
1979
1980int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1981{
1982 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001983 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001984 int err;
1985
1986 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1987 if (!cmd)
1988 return -ENOENT;
1989
Johan Hedbergac56fb12011-02-19 12:05:59 -03001990 bacpy(&rp.bdaddr, bdaddr);
1991 rp.status = status;
1992
Szymon Janc4e51eae2011-02-25 19:05:48 +01001993 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1994 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001995
Johan Hedberga664b5b2011-02-19 12:06:02 -03001996 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001997
1998 return err;
1999}
Johan Hedberga5c29682011-02-19 12:05:57 -03002000
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002001int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2002 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002003{
2004 struct mgmt_ev_user_confirm_request ev;
2005
2006 BT_DBG("hci%u", index);
2007
Johan Hedberga5c29682011-02-19 12:05:57 -03002008 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002009 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002010 put_unaligned_le32(value, &ev.value);
2011
Szymon Janc4e51eae2011-02-25 19:05:48 +01002012 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2013 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002014}
2015
2016static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2017 u8 opcode)
2018{
2019 struct pending_cmd *cmd;
2020 struct mgmt_rp_user_confirm_reply rp;
2021 int err;
2022
2023 cmd = mgmt_pending_find(opcode, index);
2024 if (!cmd)
2025 return -ENOENT;
2026
Johan Hedberga5c29682011-02-19 12:05:57 -03002027 bacpy(&rp.bdaddr, bdaddr);
2028 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002029 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002030
Johan Hedberga664b5b2011-02-19 12:06:02 -03002031 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002032
2033 return err;
2034}
2035
2036int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2037{
2038 return confirm_reply_complete(index, bdaddr, status,
2039 MGMT_OP_USER_CONFIRM_REPLY);
2040}
2041
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002042int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002043{
2044 return confirm_reply_complete(index, bdaddr, status,
2045 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2046}
Johan Hedberg2a611692011-02-19 12:06:00 -03002047
2048int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2049{
2050 struct mgmt_ev_auth_failed ev;
2051
Johan Hedberg2a611692011-02-19 12:06:00 -03002052 bacpy(&ev.bdaddr, bdaddr);
2053 ev.status = status;
2054
Szymon Janc4e51eae2011-02-25 19:05:48 +01002055 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002056}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002057
2058int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2059{
2060 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002061 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002062 struct mgmt_cp_set_local_name ev;
2063 int err;
2064
2065 memset(&ev, 0, sizeof(ev));
2066 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2067
2068 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2069 if (!cmd)
2070 goto send_event;
2071
2072 if (status) {
2073 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2074 goto failed;
2075 }
2076
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002077 hdev = hci_dev_get(index);
2078 if (hdev) {
2079 hci_dev_lock_bh(hdev);
2080 update_eir(hdev);
2081 hci_dev_unlock_bh(hdev);
2082 hci_dev_put(hdev);
2083 }
2084
Johan Hedbergb312b1612011-03-16 14:29:37 +02002085 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2086 sizeof(ev));
2087 if (err < 0)
2088 goto failed;
2089
2090send_event:
2091 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2092 cmd ? cmd->sk : NULL);
2093
2094failed:
2095 if (cmd)
2096 mgmt_pending_remove(cmd);
2097 return err;
2098}
Szymon Jancc35938b2011-03-22 13:12:21 +01002099
2100int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2101 u8 status)
2102{
2103 struct pending_cmd *cmd;
2104 int err;
2105
2106 BT_DBG("hci%u status %u", index, status);
2107
2108 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2109 if (!cmd)
2110 return -ENOENT;
2111
2112 if (status) {
2113 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2114 EIO);
2115 } else {
2116 struct mgmt_rp_read_local_oob_data rp;
2117
2118 memcpy(rp.hash, hash, sizeof(rp.hash));
2119 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2120
2121 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2122 &rp, sizeof(rp));
2123 }
2124
2125 mgmt_pending_remove(cmd);
2126
2127 return err;
2128}
Johan Hedberge17acd42011-03-30 23:57:16 +03002129
2130int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2131 u8 *eir)
2132{
2133 struct mgmt_ev_device_found ev;
2134
2135 memset(&ev, 0, sizeof(ev));
2136
2137 bacpy(&ev.bdaddr, bdaddr);
2138 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2139 ev.rssi = rssi;
2140
2141 if (eir)
2142 memcpy(ev.eir, eir, sizeof(ev.eir));
2143
2144 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2145}
Johan Hedberga88a9652011-03-30 13:18:12 +03002146
2147int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2148{
2149 struct mgmt_ev_remote_name ev;
2150
2151 memset(&ev, 0, sizeof(ev));
2152
2153 bacpy(&ev.bdaddr, bdaddr);
2154 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2155
2156 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2157}
Johan Hedberg314b2382011-04-27 10:29:57 -04002158
2159int mgmt_discovering(u16 index, u8 discovering)
2160{
2161 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2162 sizeof(discovering), NULL);
2163}