blob: 89bc36ae3120ee64ff196edef51c7047dcf2270f [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
Johannes Bergb5ad8b72011-06-01 08:54:45 +020044static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200199 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 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
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 Hedberg55ed8ca12011-01-17 14:41:05 +0200907{
908 struct hci_dev *hdev;
909 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 u16 key_count, expected_len;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200918 key_count = get_unaligned_le16(&cp->key_count);
919
920 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
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 Hedberg55ed8ca12011-01-17 14:41:05 +0200928 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200930
Szymon Janc4e51eae2011-02-25 19:05:48 +0100931 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200932 key_count);
933
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300934 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935
936 hci_link_keys_clear(hdev);
937
938 set_bit(HCI_LINK_KEYS, &hdev->flags);
939
940 if (cp->debug_keys)
941 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
942 else
943 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
944
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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200959{
960 struct hci_dev *hdev;
961 struct mgmt_cp_remove_key *cp;
962 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200963 int err;
964
965 cp = (void *) data;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200973
Gustavo F. Padovan13229012011-04-04 19:06:05 -0300974 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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
Johan Hedberg2784eb42011-01-21 13:56:35 +02001095 i = 0;
1096 list_for_each(p, &hdev->conn_hash.list) {
1097 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1098
1099 bacpy(&rp->conn[i++], &c->dst);
1100 }
1101
Szymon Janc4e51eae2011-02-25 19:05:48 +01001102 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001103
1104unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001105 kfree(rp);
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001106 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107 hci_dev_put(hdev);
1108 return err;
1109}
1110
Szymon Janc4e51eae2011-02-25 19:05:48 +01001111static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1112 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001113{
1114 struct hci_dev *hdev;
1115 struct mgmt_cp_pin_code_reply *cp;
1116 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001117 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001118 int err;
1119
1120 BT_DBG("");
1121
1122 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001123
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001124 if (len != sizeof(*cp))
1125 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1126
Szymon Janc4e51eae2011-02-25 19:05:48 +01001127 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001128 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001129 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001130
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001131 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001132
1133 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001134 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001135 goto failed;
1136 }
1137
Szymon Janc4e51eae2011-02-25 19:05:48 +01001138 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001139 if (!cmd) {
1140 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001141 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001142 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001143
1144 bacpy(&reply.bdaddr, &cp->bdaddr);
1145 reply.pin_len = cp->pin_len;
1146 memcpy(reply.pin_code, cp->pin_code, 16);
1147
1148 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1149 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001150 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001151
1152failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001153 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154 hci_dev_put(hdev);
1155
1156 return err;
1157}
1158
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1160 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001161{
1162 struct hci_dev *hdev;
1163 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001164 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001165 int err;
1166
1167 BT_DBG("");
1168
1169 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001170
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001171 if (len != sizeof(*cp))
1172 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1173 EINVAL);
1174
Szymon Janc4e51eae2011-02-25 19:05:48 +01001175 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001176 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1178 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001180 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001181
1182 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1184 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185 goto failed;
1186 }
1187
Szymon Janc4e51eae2011-02-25 19:05:48 +01001188 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001190 if (!cmd) {
1191 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001192 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001193 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001194
Szymon Janc3cf2a4f2011-03-01 16:55:33 +01001195 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
Johan Hedberg980e1a52011-01-22 06:10:07 +02001196 &cp->bdaddr);
1197 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001198 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001199
1200failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001201 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202 hci_dev_put(hdev);
1203
1204 return err;
1205}
1206
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1208 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001209{
1210 struct hci_dev *hdev;
1211 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001212
1213 BT_DBG("");
1214
1215 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001216
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001217 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001218 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001219
Szymon Janc4e51eae2011-02-25 19:05:48 +01001220 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001221 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001222 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001223
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001224 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001225
1226 hdev->io_capability = cp->io_capability;
1227
1228 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001229 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001230
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001231 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001232 hci_dev_put(hdev);
1233
Szymon Janc4e51eae2011-02-25 19:05:48 +01001234 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001235}
1236
Johan Hedberge9a416b2011-02-19 12:05:56 -03001237static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1238{
1239 struct hci_dev *hdev = conn->hdev;
1240 struct list_head *p;
1241
1242 list_for_each(p, &cmd_list) {
1243 struct pending_cmd *cmd;
1244
1245 cmd = list_entry(p, struct pending_cmd, list);
1246
1247 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1248 continue;
1249
1250 if (cmd->index != hdev->id)
1251 continue;
1252
1253 if (cmd->user_data != conn)
1254 continue;
1255
1256 return cmd;
1257 }
1258
1259 return NULL;
1260}
1261
1262static void pairing_complete(struct pending_cmd *cmd, u8 status)
1263{
1264 struct mgmt_rp_pair_device rp;
1265 struct hci_conn *conn = cmd->user_data;
1266
Johan Hedberge9a416b2011-02-19 12:05:56 -03001267 bacpy(&rp.bdaddr, &conn->dst);
1268 rp.status = status;
1269
Szymon Janc4e51eae2011-02-25 19:05:48 +01001270 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001271
1272 /* So we don't get further callbacks for this connection */
1273 conn->connect_cfm_cb = NULL;
1274 conn->security_cfm_cb = NULL;
1275 conn->disconn_cfm_cb = NULL;
1276
1277 hci_conn_put(conn);
1278
Johan Hedberga664b5b2011-02-19 12:06:02 -03001279 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001280}
1281
1282static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1283{
1284 struct pending_cmd *cmd;
1285
1286 BT_DBG("status %u", status);
1287
1288 cmd = find_pairing(conn);
1289 if (!cmd) {
1290 BT_DBG("Unable to find a pending command");
1291 return;
1292 }
1293
1294 pairing_complete(cmd, status);
1295}
1296
Szymon Janc4e51eae2011-02-25 19:05:48 +01001297static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001298{
1299 struct hci_dev *hdev;
1300 struct mgmt_cp_pair_device *cp;
1301 struct pending_cmd *cmd;
1302 u8 sec_level, auth_type;
1303 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001304 int err;
1305
1306 BT_DBG("");
1307
1308 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001309
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001310 if (len != sizeof(*cp))
1311 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1312
Szymon Janc4e51eae2011-02-25 19:05:48 +01001313 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001314 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001316
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001317 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001318
1319 if (cp->io_cap == 0x03) {
1320 sec_level = BT_SECURITY_MEDIUM;
1321 auth_type = HCI_AT_DEDICATED_BONDING;
1322 } else {
1323 sec_level = BT_SECURITY_HIGH;
1324 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1325 }
1326
1327 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001328 if (IS_ERR(conn)) {
1329 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001330 goto unlock;
1331 }
1332
1333 if (conn->connect_cfm_cb) {
1334 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001335 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336 goto unlock;
1337 }
1338
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340 if (!cmd) {
1341 err = -ENOMEM;
1342 hci_conn_put(conn);
1343 goto unlock;
1344 }
1345
1346 conn->connect_cfm_cb = pairing_complete_cb;
1347 conn->security_cfm_cb = pairing_complete_cb;
1348 conn->disconn_cfm_cb = pairing_complete_cb;
1349 conn->io_capability = cp->io_cap;
1350 cmd->user_data = conn;
1351
1352 if (conn->state == BT_CONNECTED &&
1353 hci_conn_security(conn, sec_level, auth_type))
1354 pairing_complete(cmd, 0);
1355
1356 err = 0;
1357
1358unlock:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001359 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001360 hci_dev_put(hdev);
1361
1362 return err;
1363}
1364
Szymon Janc4e51eae2011-02-25 19:05:48 +01001365static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1366 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001367{
1368 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001370 struct pending_cmd *cmd;
1371 struct hci_dev *hdev;
1372 int err;
1373
1374 BT_DBG("");
1375
Johan Hedberga5c29682011-02-19 12:05:57 -03001376 if (success) {
1377 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1378 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1379 } else {
1380 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1381 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1382 }
1383
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001384 if (len != sizeof(*cp))
1385 return cmd_status(sk, index, mgmt_op, EINVAL);
1386
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001388 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001390
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001391 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001392
Johan Hedberga5c29682011-02-19 12:05:57 -03001393 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001395 goto failed;
1396 }
1397
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001399 if (!cmd) {
1400 err = -ENOMEM;
1401 goto failed;
1402 }
1403
1404 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001405 if (err < 0)
1406 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001407
1408failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001409 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001410 hci_dev_put(hdev);
1411
1412 return err;
1413}
1414
Johan Hedbergb312b1612011-03-16 14:29:37 +02001415static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1416 u16 len)
1417{
1418 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1419 struct hci_cp_write_local_name hci_cp;
1420 struct hci_dev *hdev;
1421 struct pending_cmd *cmd;
1422 int err;
1423
1424 BT_DBG("");
1425
1426 if (len != sizeof(*mgmt_cp))
1427 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1428
1429 hdev = hci_dev_get(index);
1430 if (!hdev)
1431 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1432
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001433 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001434
1435 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1436 if (!cmd) {
1437 err = -ENOMEM;
1438 goto failed;
1439 }
1440
1441 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1442 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1443 &hci_cp);
1444 if (err < 0)
1445 mgmt_pending_remove(cmd);
1446
1447failed:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001448 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001449 hci_dev_put(hdev);
1450
1451 return err;
1452}
1453
Szymon Jancc35938b2011-03-22 13:12:21 +01001454static int read_local_oob_data(struct sock *sk, u16 index)
1455{
1456 struct hci_dev *hdev;
1457 struct pending_cmd *cmd;
1458 int err;
1459
1460 BT_DBG("hci%u", index);
1461
1462 hdev = hci_dev_get(index);
1463 if (!hdev)
1464 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1465 ENODEV);
1466
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001467 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001468
1469 if (!test_bit(HCI_UP, &hdev->flags)) {
1470 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1471 ENETDOWN);
1472 goto unlock;
1473 }
1474
1475 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1476 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1477 EOPNOTSUPP);
1478 goto unlock;
1479 }
1480
1481 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1482 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1483 goto unlock;
1484 }
1485
1486 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1487 if (!cmd) {
1488 err = -ENOMEM;
1489 goto unlock;
1490 }
1491
1492 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1493 if (err < 0)
1494 mgmt_pending_remove(cmd);
1495
1496unlock:
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001497 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001498 hci_dev_put(hdev);
1499
1500 return err;
1501}
1502
Szymon Janc2763eda2011-03-22 13:12:22 +01001503static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1504 u16 len)
1505{
1506 struct hci_dev *hdev;
1507 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1508 int err;
1509
1510 BT_DBG("hci%u ", index);
1511
1512 if (len != sizeof(*cp))
1513 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1514 EINVAL);
1515
1516 hdev = hci_dev_get(index);
1517 if (!hdev)
1518 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1519 ENODEV);
1520
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001521 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001522
1523 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1524 cp->randomizer);
1525 if (err < 0)
1526 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1527 else
1528 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1529 0);
1530
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001531 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001532 hci_dev_put(hdev);
1533
1534 return err;
1535}
1536
1537static int remove_remote_oob_data(struct sock *sk, u16 index,
1538 unsigned char *data, u16 len)
1539{
1540 struct hci_dev *hdev;
1541 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1542 int err;
1543
1544 BT_DBG("hci%u ", index);
1545
1546 if (len != sizeof(*cp))
1547 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1548 EINVAL);
1549
1550 hdev = hci_dev_get(index);
1551 if (!hdev)
1552 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1553 ENODEV);
1554
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001555 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001556
1557 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1558 if (err < 0)
1559 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1560 -err);
1561 else
1562 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1563 NULL, 0);
1564
Gustavo F. Padovan13229012011-04-04 19:06:05 -03001565 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001566 hci_dev_put(hdev);
1567
1568 return err;
1569}
1570
Johan Hedberg14a53662011-04-27 10:29:56 -04001571static int start_discovery(struct sock *sk, u16 index)
1572{
1573 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1574 struct hci_cp_inquiry cp;
1575 struct pending_cmd *cmd;
1576 struct hci_dev *hdev;
1577 int err;
1578
1579 BT_DBG("hci%u", index);
1580
1581 hdev = hci_dev_get(index);
1582 if (!hdev)
1583 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1584
1585 hci_dev_lock_bh(hdev);
1586
1587 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1588 if (!cmd) {
1589 err = -ENOMEM;
1590 goto failed;
1591 }
1592
1593 memset(&cp, 0, sizeof(cp));
1594 memcpy(&cp.lap, lap, 3);
1595 cp.length = 0x08;
1596 cp.num_rsp = 0x00;
1597
1598 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1599 if (err < 0)
1600 mgmt_pending_remove(cmd);
1601
1602failed:
1603 hci_dev_unlock_bh(hdev);
1604 hci_dev_put(hdev);
1605
1606 return err;
1607}
1608
1609static int stop_discovery(struct sock *sk, u16 index)
1610{
1611 struct hci_dev *hdev;
1612 struct pending_cmd *cmd;
1613 int err;
1614
1615 BT_DBG("hci%u", index);
1616
1617 hdev = hci_dev_get(index);
1618 if (!hdev)
1619 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1620
1621 hci_dev_lock_bh(hdev);
1622
1623 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1624 if (!cmd) {
1625 err = -ENOMEM;
1626 goto failed;
1627 }
1628
1629 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1630 if (err < 0)
1631 mgmt_pending_remove(cmd);
1632
1633failed:
1634 hci_dev_unlock_bh(hdev);
1635 hci_dev_put(hdev);
1636
1637 return err;
1638}
1639
Johan Hedberg03811012010-12-08 00:21:06 +02001640int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1641{
1642 unsigned char *buf;
1643 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001645 int err;
1646
1647 BT_DBG("got %zu bytes", msglen);
1648
1649 if (msglen < sizeof(*hdr))
1650 return -EINVAL;
1651
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001652 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001653 if (!buf)
1654 return -ENOMEM;
1655
1656 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1657 err = -EFAULT;
1658 goto done;
1659 }
1660
1661 hdr = (struct mgmt_hdr *) buf;
1662 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001663 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001664 len = get_unaligned_le16(&hdr->len);
1665
1666 if (len != msglen - sizeof(*hdr)) {
1667 err = -EINVAL;
1668 goto done;
1669 }
1670
1671 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001672 case MGMT_OP_READ_VERSION:
1673 err = read_version(sk);
1674 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001675 case MGMT_OP_READ_INDEX_LIST:
1676 err = read_index_list(sk);
1677 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001678 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001679 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001680 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001681 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001682 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001683 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001684 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001685 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001686 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001687 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001688 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001689 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001690 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001691 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001692 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001693 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001694 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001695 break;
1696 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001697 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001698 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001699 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001700 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001701 break;
1702 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001703 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001704 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001705 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001706 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001707 break;
1708 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001709 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001710 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001711 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001712 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001713 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001715 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001716 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001717 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001718 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719 break;
1720 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001721 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001722 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001723 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001724 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001725 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001727 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001728 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001729 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001730 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001731 break;
1732 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001733 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001734 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001735 case MGMT_OP_SET_LOCAL_NAME:
1736 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1737 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001738 case MGMT_OP_READ_LOCAL_OOB_DATA:
1739 err = read_local_oob_data(sk, index);
1740 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001741 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1742 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1743 break;
1744 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1745 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1746 len);
1747 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001748 case MGMT_OP_START_DISCOVERY:
1749 err = start_discovery(sk, index);
1750 break;
1751 case MGMT_OP_STOP_DISCOVERY:
1752 err = stop_discovery(sk, index);
1753 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001754 default:
1755 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001756 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001757 break;
1758 }
1759
Johan Hedberge41d8b42010-12-13 21:07:03 +02001760 if (err < 0)
1761 goto done;
1762
Johan Hedberg03811012010-12-08 00:21:06 +02001763 err = msglen;
1764
1765done:
1766 kfree(buf);
1767 return err;
1768}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001769
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001770int mgmt_index_added(u16 index)
1771{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001772 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001773}
1774
1775int mgmt_index_removed(u16 index)
1776{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001777 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001778}
1779
Johan Hedberg73f22f62010-12-29 16:00:25 +02001780struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001781 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001782 struct sock *sk;
1783};
1784
Johan Hedberg72a734e2010-12-30 00:38:22 +02001785static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001786{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001787 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001788 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001789
Johan Hedberg72a734e2010-12-30 00:38:22 +02001790 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001791 return;
1792
Johan Hedberg053f0212011-01-26 13:07:10 +02001793 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001794
1795 list_del(&cmd->list);
1796
1797 if (match->sk == NULL) {
1798 match->sk = cmd->sk;
1799 sock_hold(match->sk);
1800 }
1801
1802 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001803}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001804
1805int mgmt_powered(u16 index, u8 powered)
1806{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001807 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001808 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001809 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001810
Johan Hedberg72a734e2010-12-30 00:38:22 +02001811 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001812
Johan Hedberg72a734e2010-12-30 00:38:22 +02001813 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001814
Szymon Janc4e51eae2011-02-25 19:05:48 +01001815 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001816
1817 if (match.sk)
1818 sock_put(match.sk);
1819
1820 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001821}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001822
Johan Hedberg73f22f62010-12-29 16:00:25 +02001823int mgmt_discoverable(u16 index, u8 discoverable)
1824{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001825 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001826 struct cmd_lookup match = { discoverable, NULL };
1827 int ret;
1828
Szymon Jancb8534e02011-03-01 16:55:34 +01001829 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001830
Johan Hedberg72a734e2010-12-30 00:38:22 +02001831 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001832
Szymon Janc4e51eae2011-02-25 19:05:48 +01001833 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1834 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001835
1836 if (match.sk)
1837 sock_put(match.sk);
1838
1839 return ret;
1840}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001841
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001842int mgmt_connectable(u16 index, u8 connectable)
1843{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001844 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001845 struct cmd_lookup match = { connectable, NULL };
1846 int ret;
1847
Johan Hedberg72a734e2010-12-30 00:38:22 +02001848 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001849
Johan Hedberg72a734e2010-12-30 00:38:22 +02001850 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001851
Szymon Janc4e51eae2011-02-25 19:05:48 +01001852 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001853
1854 if (match.sk)
1855 sock_put(match.sk);
1856
1857 return ret;
1858}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001859
Johan Hedberg4df378a2011-04-28 11:29:03 -07001860int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861{
1862 struct mgmt_ev_new_key ev;
1863
1864 memset(&ev, 0, sizeof(ev));
1865
Johan Hedberg4df378a2011-04-28 11:29:03 -07001866 ev.store_hint = persistent;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001867 bacpy(&ev.key.bdaddr, &key->bdaddr);
1868 ev.key.type = key->type;
1869 memcpy(ev.key.val, key->val, 16);
1870 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001873}
Johan Hedbergf7520542011-01-20 12:34:39 +02001874
1875int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1876{
1877 struct mgmt_ev_connected ev;
1878
Johan Hedbergf7520542011-01-20 12:34:39 +02001879 bacpy(&ev.bdaddr, bdaddr);
1880
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001882}
1883
Johan Hedberg8962ee72011-01-20 12:40:27 +02001884static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1885{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001886 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001887 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001888 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001889
Johan Hedberga38528f2011-01-22 06:46:43 +02001890 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001891
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001893
1894 *sk = cmd->sk;
1895 sock_hold(*sk);
1896
Johan Hedberga664b5b2011-02-19 12:06:02 -03001897 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001898}
1899
Johan Hedbergf7520542011-01-20 12:34:39 +02001900int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1901{
1902 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001903 struct sock *sk = NULL;
1904 int err;
1905
1906 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001907
Johan Hedbergf7520542011-01-20 12:34:39 +02001908 bacpy(&ev.bdaddr, bdaddr);
1909
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001911
1912 if (sk)
1913 sock_put(sk);
1914
1915 return err;
1916}
1917
1918int mgmt_disconnect_failed(u16 index)
1919{
1920 struct pending_cmd *cmd;
1921 int err;
1922
1923 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1924 if (!cmd)
1925 return -ENOENT;
1926
Szymon Janc4e51eae2011-02-25 19:05:48 +01001927 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001928
Johan Hedberga664b5b2011-02-19 12:06:02 -03001929 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001930
1931 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001932}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001933
1934int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1935{
1936 struct mgmt_ev_connect_failed ev;
1937
Johan Hedberg17d5c042011-01-22 06:09:08 +02001938 bacpy(&ev.bdaddr, bdaddr);
1939 ev.status = status;
1940
Szymon Janc4e51eae2011-02-25 19:05:48 +01001941 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001942}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001943
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02001944int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001945{
1946 struct mgmt_ev_pin_code_request ev;
1947
Johan Hedberg980e1a52011-01-22 06:10:07 +02001948 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02001949 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001950
Szymon Janc4e51eae2011-02-25 19:05:48 +01001951 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1952 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001953}
1954
1955int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1956{
1957 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001958 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001959 int err;
1960
1961 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1962 if (!cmd)
1963 return -ENOENT;
1964
Johan Hedbergac56fb12011-02-19 12:05:59 -03001965 bacpy(&rp.bdaddr, bdaddr);
1966 rp.status = status;
1967
Szymon Janc4e51eae2011-02-25 19:05:48 +01001968 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1969 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001970
Johan Hedberga664b5b2011-02-19 12:06:02 -03001971 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001972
1973 return err;
1974}
1975
1976int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1977{
1978 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001979 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001980 int err;
1981
1982 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1983 if (!cmd)
1984 return -ENOENT;
1985
Johan Hedbergac56fb12011-02-19 12:05:59 -03001986 bacpy(&rp.bdaddr, bdaddr);
1987 rp.status = status;
1988
Szymon Janc4e51eae2011-02-25 19:05:48 +01001989 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1990 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001991
Johan Hedberga664b5b2011-02-19 12:06:02 -03001992 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001993
1994 return err;
1995}
Johan Hedberga5c29682011-02-19 12:05:57 -03001996
Johan Hedberg55bc1a32011-04-28 11:28:56 -07001997int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
1998 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03001999{
2000 struct mgmt_ev_user_confirm_request ev;
2001
2002 BT_DBG("hci%u", index);
2003
Johan Hedberga5c29682011-02-19 12:05:57 -03002004 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002005 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002006 put_unaligned_le32(value, &ev.value);
2007
Szymon Janc4e51eae2011-02-25 19:05:48 +01002008 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2009 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002010}
2011
2012static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2013 u8 opcode)
2014{
2015 struct pending_cmd *cmd;
2016 struct mgmt_rp_user_confirm_reply rp;
2017 int err;
2018
2019 cmd = mgmt_pending_find(opcode, index);
2020 if (!cmd)
2021 return -ENOENT;
2022
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 bacpy(&rp.bdaddr, bdaddr);
2024 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002025 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002026
Johan Hedberga664b5b2011-02-19 12:06:02 -03002027 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002028
2029 return err;
2030}
2031
2032int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2033{
2034 return confirm_reply_complete(index, bdaddr, status,
2035 MGMT_OP_USER_CONFIRM_REPLY);
2036}
2037
Szymon Jancb8534e02011-03-01 16:55:34 +01002038int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002039{
2040 return confirm_reply_complete(index, bdaddr, status,
2041 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2042}
Johan Hedberg2a611692011-02-19 12:06:00 -03002043
2044int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2045{
2046 struct mgmt_ev_auth_failed ev;
2047
Johan Hedberg2a611692011-02-19 12:06:00 -03002048 bacpy(&ev.bdaddr, bdaddr);
2049 ev.status = status;
2050
Szymon Janc4e51eae2011-02-25 19:05:48 +01002051 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002052}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002053
2054int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2055{
2056 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002057 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002058 struct mgmt_cp_set_local_name ev;
2059 int err;
2060
2061 memset(&ev, 0, sizeof(ev));
2062 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2063
2064 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2065 if (!cmd)
2066 goto send_event;
2067
2068 if (status) {
2069 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2070 goto failed;
2071 }
2072
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002073 hdev = hci_dev_get(index);
2074 if (hdev) {
2075 hci_dev_lock_bh(hdev);
2076 update_eir(hdev);
2077 hci_dev_unlock_bh(hdev);
2078 hci_dev_put(hdev);
2079 }
2080
Johan Hedbergb312b1612011-03-16 14:29:37 +02002081 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2082 sizeof(ev));
2083 if (err < 0)
2084 goto failed;
2085
2086send_event:
2087 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2088 cmd ? cmd->sk : NULL);
2089
2090failed:
2091 if (cmd)
2092 mgmt_pending_remove(cmd);
2093 return err;
2094}
Szymon Jancc35938b2011-03-22 13:12:21 +01002095
2096int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2097 u8 status)
2098{
2099 struct pending_cmd *cmd;
2100 int err;
2101
2102 BT_DBG("hci%u status %u", index, status);
2103
2104 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2105 if (!cmd)
2106 return -ENOENT;
2107
2108 if (status) {
2109 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2110 EIO);
2111 } else {
2112 struct mgmt_rp_read_local_oob_data rp;
2113
2114 memcpy(rp.hash, hash, sizeof(rp.hash));
2115 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2116
2117 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2118 &rp, sizeof(rp));
2119 }
2120
2121 mgmt_pending_remove(cmd);
2122
2123 return err;
2124}
Johan Hedberge17acd42011-03-30 23:57:16 +03002125
2126int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2127 u8 *eir)
2128{
2129 struct mgmt_ev_device_found ev;
2130
2131 memset(&ev, 0, sizeof(ev));
2132
2133 bacpy(&ev.bdaddr, bdaddr);
2134 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2135 ev.rssi = rssi;
2136
2137 if (eir)
2138 memcpy(ev.eir, eir, sizeof(ev.eir));
2139
2140 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2141}
Johan Hedberga88a9652011-03-30 13:18:12 +03002142
2143int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2144{
2145 struct mgmt_ev_remote_name ev;
2146
2147 memset(&ev, 0, sizeof(ev));
2148
2149 bacpy(&ev.bdaddr, bdaddr);
2150 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2151
2152 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2153}
Johan Hedberg314b2382011-04-27 10:29:57 -04002154
2155int mgmt_discovering(u16 index, u8 discovering)
2156{
2157 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2158 sizeof(discovering), NULL);
2159}