blob: 2145168c89f125af84f8d16a4ca3c07996b87dc2 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044LIST_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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 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 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 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;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300911 int i, err;
Johan Hedberg55ed8ca2011-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 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);
Vinicius Costa Gomesc00ddbf2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200924 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 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
Vinicius Costa Gomesc00ddbf2011-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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300954 struct key_master_id *id = (void *) key->data;
955
956 if (key->dlen != sizeof(struct key_master_id))
957 continue;
958
Vinicius Costa Gomes1fa2de32011-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 Gomesc00ddbf2011-07-08 18:31:44 -0300961
962 continue;
963 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200966 key->pin_len);
967 }
968
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300969 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200972 hci_dev_put(hdev);
973
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300974 return err;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200978{
979 struct hci_dev *hdev;
980 struct mgmt_cp_remove_key *cp;
981 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200982 int err;
983
984 cp = (void *) data;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001013 }
1014
1015unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 hci_dev_lock(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);
1055 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001056 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1057 if (!conn) {
1058 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1059 ENOTCONN);
1060 goto failed;
1061 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001062 }
1063
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001065 if (!cmd) {
1066 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001067 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001068 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069
1070 put_unaligned_le16(conn->handle, &dc.handle);
1071 dc.reason = 0x13; /* Remote User Terminated Connection */
1072
1073 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1074 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001075 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001076
1077failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001079 hci_dev_put(hdev);
1080
1081 return err;
1082}
1083
Szymon Janc8ce62842011-03-01 16:55:32 +01001084static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001085{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001086 struct mgmt_rp_get_connections *rp;
1087 struct hci_dev *hdev;
1088 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001089 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001090 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001091 int i, err;
1092
1093 BT_DBG("");
1094
Szymon Janc4e51eae2011-02-25 19:05:48 +01001095 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001096 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001097 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001100
1101 count = 0;
1102 list_for_each(p, &hdev->conn_hash.list) {
1103 count++;
1104 }
1105
Johan Hedberga38528f2011-01-22 06:46:43 +02001106 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1107 rp = kmalloc(rp_len, GFP_ATOMIC);
1108 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001109 err = -ENOMEM;
1110 goto unlock;
1111 }
1112
Johan Hedberg2784eb42011-01-21 13:56:35 +02001113 put_unaligned_le16(count, &rp->conn_count);
1114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 read_lock(&hci_dev_list_lock);
1116
Johan Hedberg2784eb42011-01-21 13:56:35 +02001117 i = 0;
1118 list_for_each(p, &hdev->conn_hash.list) {
1119 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1120
1121 bacpy(&rp->conn[i++], &c->dst);
1122 }
1123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 read_unlock(&hci_dev_list_lock);
1125
Szymon Janc4e51eae2011-02-25 19:05:48 +01001126 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001127
1128unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001129 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001131 hci_dev_put(hdev);
1132 return err;
1133}
1134
Szymon Janc4e51eae2011-02-25 19:05:48 +01001135static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1136 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001137{
1138 struct hci_dev *hdev;
1139 struct mgmt_cp_pin_code_reply *cp;
1140 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001141 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001142 int err;
1143
1144 BT_DBG("");
1145
1146 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001147
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001148 if (len != sizeof(*cp))
1149 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1150
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001153 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001156
1157 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001158 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001159 goto failed;
1160 }
1161
Szymon Janc4e51eae2011-02-25 19:05:48 +01001162 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001163 if (!cmd) {
1164 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001165 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001166 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001167
1168 bacpy(&reply.bdaddr, &cp->bdaddr);
1169 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001171
1172 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1173 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001174 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001175
1176failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001178 hci_dev_put(hdev);
1179
1180 return err;
1181}
1182
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1184 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185{
1186 struct hci_dev *hdev;
1187 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189 int err;
1190
1191 BT_DBG("");
1192
1193 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001194
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001195 if (len != sizeof(*cp))
1196 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1197 EINVAL);
1198
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001201 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1202 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205
1206 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1208 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001209 goto failed;
1210 }
1211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1213 data, len);
1214 if (!cmd) {
1215 err = -ENOMEM;
1216 goto failed;
1217 }
1218
1219 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1220 &cp->bdaddr);
1221 if (err < 0)
1222 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001223
1224failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001226 hci_dev_put(hdev);
1227
1228 return err;
1229}
1230
Szymon Janc4e51eae2011-02-25 19:05:48 +01001231static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1232 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001233{
1234 struct hci_dev *hdev;
1235 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001236
1237 BT_DBG("");
1238
1239 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001240
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001241 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001242 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001243
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001245 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001249
1250 hdev->io_capability = cp->io_capability;
1251
1252 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001253 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001256 hci_dev_put(hdev);
1257
Szymon Janc4e51eae2011-02-25 19:05:48 +01001258 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001259}
1260
Johan Hedberge9a416b2011-02-19 12:05:56 -03001261static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1262{
1263 struct hci_dev *hdev = conn->hdev;
1264 struct list_head *p;
1265
1266 list_for_each(p, &cmd_list) {
1267 struct pending_cmd *cmd;
1268
1269 cmd = list_entry(p, struct pending_cmd, list);
1270
1271 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1272 continue;
1273
1274 if (cmd->index != hdev->id)
1275 continue;
1276
1277 if (cmd->user_data != conn)
1278 continue;
1279
1280 return cmd;
1281 }
1282
1283 return NULL;
1284}
1285
1286static void pairing_complete(struct pending_cmd *cmd, u8 status)
1287{
1288 struct mgmt_rp_pair_device rp;
1289 struct hci_conn *conn = cmd->user_data;
1290
Johan Hedberge9a416b2011-02-19 12:05:56 -03001291 bacpy(&rp.bdaddr, &conn->dst);
1292 rp.status = status;
1293
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001295
1296 /* So we don't get further callbacks for this connection */
1297 conn->connect_cfm_cb = NULL;
1298 conn->security_cfm_cb = NULL;
1299 conn->disconn_cfm_cb = NULL;
1300
1301 hci_conn_put(conn);
1302
Johan Hedberga664b5b2011-02-19 12:06:02 -03001303 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001304}
1305
1306static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1307{
1308 struct pending_cmd *cmd;
1309
1310 BT_DBG("status %u", status);
1311
1312 cmd = find_pairing(conn);
1313 if (!cmd) {
1314 BT_DBG("Unable to find a pending command");
1315 return;
1316 }
1317
1318 pairing_complete(cmd, status);
1319}
1320
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322{
1323 struct hci_dev *hdev;
1324 struct mgmt_cp_pair_device *cp;
1325 struct pending_cmd *cmd;
1326 u8 sec_level, auth_type;
1327 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001328 int err;
1329
1330 BT_DBG("");
1331
1332 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001334 if (len != sizeof(*cp))
1335 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1336
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001342
1343 if (cp->io_cap == 0x03) {
1344 sec_level = BT_SECURITY_MEDIUM;
1345 auth_type = HCI_AT_DEDICATED_BONDING;
1346 } else {
1347 sec_level = BT_SECURITY_HIGH;
1348 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1349 }
1350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1352 auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001353 if (IS_ERR(conn)) {
1354 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355 goto unlock;
1356 }
1357
1358 if (conn->connect_cfm_cb) {
1359 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001360 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001361 goto unlock;
1362 }
1363
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365 if (!cmd) {
1366 err = -ENOMEM;
1367 hci_conn_put(conn);
1368 goto unlock;
1369 }
1370
1371 conn->connect_cfm_cb = pairing_complete_cb;
1372 conn->security_cfm_cb = pairing_complete_cb;
1373 conn->disconn_cfm_cb = pairing_complete_cb;
1374 conn->io_capability = cp->io_cap;
1375 cmd->user_data = conn;
1376
1377 if (conn->state == BT_CONNECTED &&
1378 hci_conn_security(conn, sec_level, auth_type))
1379 pairing_complete(cmd, 0);
1380
1381 err = 0;
1382
1383unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001385 hci_dev_put(hdev);
1386
1387 return err;
1388}
1389
Szymon Janc4e51eae2011-02-25 19:05:48 +01001390static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1391 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001392{
1393 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001395 struct pending_cmd *cmd;
1396 struct hci_dev *hdev;
1397 int err;
1398
1399 BT_DBG("");
1400
Johan Hedberga5c29682011-02-19 12:05:57 -03001401 if (success) {
1402 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1403 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1404 } else {
1405 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1406 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1407 }
1408
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001409 if (len != sizeof(*cp))
1410 return cmd_status(sk, index, mgmt_op, EINVAL);
1411
Szymon Janc4e51eae2011-02-25 19:05:48 +01001412 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001413 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001414 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001417
Johan Hedberga5c29682011-02-19 12:05:57 -03001418 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001420 goto failed;
1421 }
1422
Szymon Janc4e51eae2011-02-25 19:05:48 +01001423 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001424 if (!cmd) {
1425 err = -ENOMEM;
1426 goto failed;
1427 }
1428
1429 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001430 if (err < 0)
1431 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001432
1433failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001435 hci_dev_put(hdev);
1436
1437 return err;
1438}
1439
Johan Hedbergb312b1612011-03-16 14:29:37 +02001440static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1441 u16 len)
1442{
1443 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1444 struct hci_cp_write_local_name hci_cp;
1445 struct hci_dev *hdev;
1446 struct pending_cmd *cmd;
1447 int err;
1448
1449 BT_DBG("");
1450
1451 if (len != sizeof(*mgmt_cp))
1452 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1453
1454 hdev = hci_dev_get(index);
1455 if (!hdev)
1456 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001459
1460 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1461 if (!cmd) {
1462 err = -ENOMEM;
1463 goto failed;
1464 }
1465
1466 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1467 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1468 &hci_cp);
1469 if (err < 0)
1470 mgmt_pending_remove(cmd);
1471
1472failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001474 hci_dev_put(hdev);
1475
1476 return err;
1477}
1478
Szymon Jancc35938b2011-03-22 13:12:21 +01001479static int read_local_oob_data(struct sock *sk, u16 index)
1480{
1481 struct hci_dev *hdev;
1482 struct pending_cmd *cmd;
1483 int err;
1484
1485 BT_DBG("hci%u", index);
1486
1487 hdev = hci_dev_get(index);
1488 if (!hdev)
1489 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1490 ENODEV);
1491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001493
1494 if (!test_bit(HCI_UP, &hdev->flags)) {
1495 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1496 ENETDOWN);
1497 goto unlock;
1498 }
1499
1500 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1501 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1502 EOPNOTSUPP);
1503 goto unlock;
1504 }
1505
1506 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1507 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1508 goto unlock;
1509 }
1510
1511 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1512 if (!cmd) {
1513 err = -ENOMEM;
1514 goto unlock;
1515 }
1516
1517 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1518 if (err < 0)
1519 mgmt_pending_remove(cmd);
1520
1521unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001523 hci_dev_put(hdev);
1524
1525 return err;
1526}
1527
Szymon Janc2763eda2011-03-22 13:12:22 +01001528static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1529 u16 len)
1530{
1531 struct hci_dev *hdev;
1532 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1533 int err;
1534
1535 BT_DBG("hci%u ", index);
1536
1537 if (len != sizeof(*cp))
1538 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1539 EINVAL);
1540
1541 hdev = hci_dev_get(index);
1542 if (!hdev)
1543 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1544 ENODEV);
1545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001547
1548 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1549 cp->randomizer);
1550 if (err < 0)
1551 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1552 else
1553 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1554 0);
1555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001557 hci_dev_put(hdev);
1558
1559 return err;
1560}
1561
1562static int remove_remote_oob_data(struct sock *sk, u16 index,
1563 unsigned char *data, u16 len)
1564{
1565 struct hci_dev *hdev;
1566 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1567 int err;
1568
1569 BT_DBG("hci%u ", index);
1570
1571 if (len != sizeof(*cp))
1572 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1573 EINVAL);
1574
1575 hdev = hci_dev_get(index);
1576 if (!hdev)
1577 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1578 ENODEV);
1579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001581
1582 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1583 if (err < 0)
1584 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1585 -err);
1586 else
1587 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1588 NULL, 0);
1589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03001591 hci_dev_put(hdev);
1592
1593 return err;
1594}
1595
Johan Hedberg03811012010-12-08 00:21:06 +02001596int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1597{
1598 unsigned char *buf;
1599 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001600 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001601 int err;
1602
1603 BT_DBG("got %zu bytes", msglen);
1604
1605 if (msglen < sizeof(*hdr))
1606 return -EINVAL;
1607
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001608 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001609 if (!buf)
1610 return -ENOMEM;
1611
1612 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1613 err = -EFAULT;
1614 goto done;
1615 }
1616
1617 hdr = (struct mgmt_hdr *) buf;
1618 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001619 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001620 len = get_unaligned_le16(&hdr->len);
1621
1622 if (len != msglen - sizeof(*hdr)) {
1623 err = -EINVAL;
1624 goto done;
1625 }
1626
1627 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001628 case MGMT_OP_READ_VERSION:
1629 err = read_version(sk);
1630 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001631 case MGMT_OP_READ_INDEX_LIST:
1632 err = read_index_list(sk);
1633 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001634 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001635 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001636 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001637 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001638 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001639 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001640 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001641 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001642 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001643 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001645 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001646 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001647 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001648 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001650 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001651 break;
1652 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001653 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001654 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001655 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001656 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001657 break;
1658 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001659 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001660 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001661 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001662 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001663 break;
1664 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001665 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001666 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001667 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001668 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001669 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001670 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001671 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001673 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001674 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001675 break;
1676 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001677 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001678 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001679 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001680 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001681 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001682 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001683 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001684 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001685 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001686 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001687 break;
1688 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001689 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001690 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001691 case MGMT_OP_SET_LOCAL_NAME:
1692 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1693 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001694 case MGMT_OP_READ_LOCAL_OOB_DATA:
1695 err = read_local_oob_data(sk, index);
1696 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001697 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1698 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1699 break;
1700 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1701 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1702 len);
1703 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704
Johan Hedberg03811012010-12-08 00:21:06 +02001705 default:
1706 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001707 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001708 break;
1709 }
1710
Johan Hedberge41d8b42010-12-13 21:07:03 +02001711 if (err < 0)
1712 goto done;
1713
Johan Hedberg03811012010-12-08 00:21:06 +02001714 err = msglen;
1715
1716done:
1717 kfree(buf);
1718 return err;
1719}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001720
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001721int mgmt_index_added(u16 index)
1722{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001723 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001724}
1725
1726int mgmt_index_removed(u16 index)
1727{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001728 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001729}
1730
Johan Hedberg73f22f62010-12-29 16:00:25 +02001731struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001732 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001733 struct sock *sk;
1734};
1735
Johan Hedberg72a734e2010-12-30 00:38:22 +02001736static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001737{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001738 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001739 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001740
Johan Hedberg72a734e2010-12-30 00:38:22 +02001741 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001742 return;
1743
Johan Hedberg053f0212011-01-26 13:07:10 +02001744 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001745
1746 list_del(&cmd->list);
1747
1748 if (match->sk == NULL) {
1749 match->sk = cmd->sk;
1750 sock_hold(match->sk);
1751 }
1752
1753 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001754}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001755
1756int mgmt_powered(u16 index, u8 powered)
1757{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001758 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001759 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001760 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001761
Johan Hedberg72a734e2010-12-30 00:38:22 +02001762 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001763
Johan Hedberg72a734e2010-12-30 00:38:22 +02001764 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001765
Szymon Janc4e51eae2011-02-25 19:05:48 +01001766 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001767
1768 if (match.sk)
1769 sock_put(match.sk);
1770
1771 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001772}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001773
Johan Hedberg73f22f62010-12-29 16:00:25 +02001774int mgmt_discoverable(u16 index, u8 discoverable)
1775{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001776 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001777 struct cmd_lookup match = { discoverable, NULL };
1778 int ret;
1779
Szymon Jancb8534e02011-03-01 16:55:34 +01001780 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001781
Johan Hedberg72a734e2010-12-30 00:38:22 +02001782 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001783
Szymon Janc4e51eae2011-02-25 19:05:48 +01001784 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1785 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001786
1787 if (match.sk)
1788 sock_put(match.sk);
1789
1790 return ret;
1791}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001792
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001793int mgmt_connectable(u16 index, u8 connectable)
1794{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001795 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001796 struct cmd_lookup match = { connectable, NULL };
1797 int ret;
1798
Johan Hedberg72a734e2010-12-30 00:38:22 +02001799 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001800
Johan Hedberg72a734e2010-12-30 00:38:22 +02001801 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001802
Szymon Janc4e51eae2011-02-25 19:05:48 +01001803 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001804
1805 if (match.sk)
1806 sock_put(match.sk);
1807
1808 return ret;
1809}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001812{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001813 struct mgmt_ev_new_key *ev;
1814 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001815
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001816 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
1817 ev = kzalloc(total, GFP_ATOMIC);
1818 if (!ev)
1819 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001820
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001821 bacpy(&ev->key.bdaddr, &key->bdaddr);
1822 ev->key.type = key->type;
1823 memcpy(ev->key.val, key->val, 16);
1824 ev->key.pin_len = key->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 ev->old_key_type = old_key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001826 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001827
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001828 memcpy(ev->key.data, key->data, key->dlen);
1829
1830 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
1831
1832 kfree(ev);
1833
1834 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001835}
Johan Hedbergf7520542011-01-20 12:34:39 +02001836
1837int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1838{
1839 struct mgmt_ev_connected ev;
1840
Johan Hedbergf7520542011-01-20 12:34:39 +02001841 bacpy(&ev.bdaddr, bdaddr);
1842
Szymon Janc4e51eae2011-02-25 19:05:48 +01001843 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001844}
1845
Johan Hedberg8962ee72011-01-20 12:40:27 +02001846static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1847{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001848 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001849 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001850 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001851
Johan Hedberga38528f2011-01-22 06:46:43 +02001852 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001853
Szymon Janc4e51eae2011-02-25 19:05:48 +01001854 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001855
1856 *sk = cmd->sk;
1857 sock_hold(*sk);
1858
Johan Hedberga664b5b2011-02-19 12:06:02 -03001859 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001860}
1861
Johan Hedbergf7520542011-01-20 12:34:39 +02001862int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1863{
1864 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001865 struct sock *sk = NULL;
1866 int err;
1867
1868 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001869
Johan Hedbergf7520542011-01-20 12:34:39 +02001870 bacpy(&ev.bdaddr, bdaddr);
1871
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001873
1874 if (sk)
1875 sock_put(sk);
1876
1877 return err;
1878}
1879
1880int mgmt_disconnect_failed(u16 index)
1881{
1882 struct pending_cmd *cmd;
1883 int err;
1884
1885 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1886 if (!cmd)
1887 return -ENOENT;
1888
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001890
Johan Hedberga664b5b2011-02-19 12:06:02 -03001891 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001892
1893 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001894}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001895
1896int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1897{
1898 struct mgmt_ev_connect_failed ev;
1899
Johan Hedberg17d5c042011-01-22 06:09:08 +02001900 bacpy(&ev.bdaddr, bdaddr);
1901 ev.status = status;
1902
Szymon Janc4e51eae2011-02-25 19:05:48 +01001903 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001904}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001907{
1908 struct mgmt_ev_pin_code_request ev;
1909
Johan Hedberg980e1a52011-01-22 06:10:07 +02001910 bacpy(&ev.bdaddr, bdaddr);
1911
Szymon Janc4e51eae2011-02-25 19:05:48 +01001912 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1913 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001914}
1915
1916int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1917{
1918 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001919 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001920 int err;
1921
1922 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1923 if (!cmd)
1924 return -ENOENT;
1925
Johan Hedbergac56fb12011-02-19 12:05:59 -03001926 bacpy(&rp.bdaddr, bdaddr);
1927 rp.status = status;
1928
Szymon Janc4e51eae2011-02-25 19:05:48 +01001929 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1930 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001931
Johan Hedberga664b5b2011-02-19 12:06:02 -03001932 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001933
1934 return err;
1935}
1936
1937int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1938{
1939 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001940 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001941 int err;
1942
1943 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1944 if (!cmd)
1945 return -ENOENT;
1946
Johan Hedbergac56fb12011-02-19 12:05:59 -03001947 bacpy(&rp.bdaddr, bdaddr);
1948 rp.status = status;
1949
Szymon Janc4e51eae2011-02-25 19:05:48 +01001950 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1951 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001952
Johan Hedberga664b5b2011-02-19 12:06:02 -03001953 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001954
1955 return err;
1956}
Johan Hedberga5c29682011-02-19 12:05:57 -03001957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03001959{
1960 struct mgmt_ev_user_confirm_request ev;
1961
1962 BT_DBG("hci%u", index);
1963
Johan Hedberga5c29682011-02-19 12:05:57 -03001964 bacpy(&ev.bdaddr, bdaddr);
1965 put_unaligned_le32(value, &ev.value);
1966
Szymon Janc4e51eae2011-02-25 19:05:48 +01001967 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1968 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001969}
1970
1971static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1972 u8 opcode)
1973{
1974 struct pending_cmd *cmd;
1975 struct mgmt_rp_user_confirm_reply rp;
1976 int err;
1977
1978 cmd = mgmt_pending_find(opcode, index);
1979 if (!cmd)
1980 return -ENOENT;
1981
Johan Hedberga5c29682011-02-19 12:05:57 -03001982 bacpy(&rp.bdaddr, bdaddr);
1983 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001984 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001985
Johan Hedberga664b5b2011-02-19 12:06:02 -03001986 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001987
1988 return err;
1989}
1990
1991int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1992{
1993 return confirm_reply_complete(index, bdaddr, status,
1994 MGMT_OP_USER_CONFIRM_REPLY);
1995}
1996
Szymon Jancb8534e02011-03-01 16:55:34 +01001997int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001998{
1999 return confirm_reply_complete(index, bdaddr, status,
2000 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2001}
Johan Hedberg2a611692011-02-19 12:06:00 -03002002
2003int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2004{
2005 struct mgmt_ev_auth_failed ev;
2006
Johan Hedberg2a611692011-02-19 12:06:00 -03002007 bacpy(&ev.bdaddr, bdaddr);
2008 ev.status = status;
2009
Szymon Janc4e51eae2011-02-25 19:05:48 +01002010 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002011}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002012
2013int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2014{
2015 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002016 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002017 struct mgmt_cp_set_local_name ev;
2018 int err;
2019
2020 memset(&ev, 0, sizeof(ev));
2021 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2022
2023 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2024 if (!cmd)
2025 goto send_event;
2026
2027 if (status) {
2028 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2029 goto failed;
2030 }
2031
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002032 hdev = hci_dev_get(index);
2033 if (hdev) {
2034 hci_dev_lock_bh(hdev);
2035 update_eir(hdev);
2036 hci_dev_unlock_bh(hdev);
2037 hci_dev_put(hdev);
2038 }
2039
Johan Hedbergb312b1612011-03-16 14:29:37 +02002040 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2041 sizeof(ev));
2042 if (err < 0)
2043 goto failed;
2044
2045send_event:
2046 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2047 cmd ? cmd->sk : NULL);
2048
2049failed:
2050 if (cmd)
2051 mgmt_pending_remove(cmd);
2052 return err;
2053}
Szymon Jancc35938b2011-03-22 13:12:21 +01002054
2055int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2056 u8 status)
2057{
2058 struct pending_cmd *cmd;
2059 int err;
2060
2061 BT_DBG("hci%u status %u", index, status);
2062
2063 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2064 if (!cmd)
2065 return -ENOENT;
2066
2067 if (status) {
2068 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2069 EIO);
2070 } else {
2071 struct mgmt_rp_read_local_oob_data rp;
2072
2073 memcpy(rp.hash, hash, sizeof(rp.hash));
2074 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2075
2076 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2077 &rp, sizeof(rp));
2078 }
2079
2080 mgmt_pending_remove(cmd);
2081
2082 return err;
2083}
Johan Hedberge17acd42011-03-30 23:57:16 +03002084
2085int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2086 u8 *eir)
2087{
2088 struct mgmt_ev_device_found ev;
2089
2090 memset(&ev, 0, sizeof(ev));
2091
2092 bacpy(&ev.bdaddr, bdaddr);
2093 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2094 ev.rssi = rssi;
2095
2096 if (eir)
2097 memcpy(ev.eir, eir, sizeof(ev.eir));
2098
2099 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2100}
Johan Hedberga88a9652011-03-30 13:18:12 +03002101
2102int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2103{
2104 struct mgmt_ev_remote_name ev;
2105
2106 memset(&ev, 0, sizeof(ev));
2107
2108 bacpy(&ev.bdaddr, bdaddr);
2109 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2110
2111 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2112}