blob: 45b7a4e5aa420d742e50b810dab36bc96df00ccd [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
Andre Guedes8c156c32011-07-07 10:30:36 -0300182 hci_dev_lock_bh(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
Andre Guedes8c156c32011-07-07 10:30:36 -0300211 hci_dev_unlock_bh(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
Andre Guedes8c156c32011-07-07 10:30:36 -0300319 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200320
321 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200322 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 goto failed;
325 }
326
Szymon Janc4e51eae2011-02-25 19:05:48 +0100327 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
328 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 goto failed;
330 }
331
Szymon Janc4e51eae2011-02-25 19:05:48 +0100332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 if (!cmd) {
334 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300336 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Johan Hedberg72a734e2010-12-30 00:38:22 +0200338 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 queue_work(hdev->workqueue, &hdev->power_on);
340 else
341 queue_work(hdev->workqueue, &hdev->power_off);
342
Johan Hedberg366a0332011-02-19 12:05:55 -0300343 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344
345failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300346 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200347 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200349}
350
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
352 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200354 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300356 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357 u8 scan;
358 int err;
359
360 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100364 if (len != sizeof(*cp))
365 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
366
Szymon Janc4e51eae2011-02-25 19:05:48 +0100367 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200370
Andre Guedes8c156c32011-07-07 10:30:36 -0300371 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200375 goto failed;
376 }
377
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
380 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 goto failed;
382 }
383
Johan Hedberg72a734e2010-12-30 00:38:22 +0200384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387 goto failed;
388 }
389
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 if (!cmd) {
392 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
396 scan = SCAN_PAGE;
397
Johan Hedberg72a734e2010-12-30 00:38:22 +0200398 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399 scan |= SCAN_INQUIRY;
400
401 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
402 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300403 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404
405failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300406 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200407 hci_dev_put(hdev);
408
409 return err;
410}
411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
413 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200414{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200415 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200416 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300417 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418 u8 scan;
419 int err;
420
421 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100425 if (len != sizeof(*cp))
426 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
427
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431
Andre Guedes8c156c32011-07-07 10:30:36 -0300432 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433
434 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200436 goto failed;
437 }
438
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100446 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200447 goto failed;
448 }
449
Szymon Janc4e51eae2011-02-25 19:05:48 +0100450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 if (!cmd) {
452 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300454 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200455
Johan Hedberg72a734e2010-12-30 00:38:22 +0200456 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 scan = SCAN_PAGE;
458 else
459 scan = 0;
460
461 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
462 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300463 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464
465failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300466 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200467 hci_dev_put(hdev);
468
469 return err;
470}
471
Szymon Janc4e51eae2011-02-25 19:05:48 +0100472static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
473 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200474{
475 struct sk_buff *skb;
476 struct mgmt_hdr *hdr;
477
478 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
479 if (!skb)
480 return -ENOMEM;
481
482 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
483
484 hdr = (void *) skb_put(skb, sizeof(*hdr));
485 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100486 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200487 hdr->len = cpu_to_le16(data_len);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
Johan Hedberg053f0212011-01-26 13:07:10 +0200498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200501
Johan Hedberga38528f2011-01-22 06:46:43 +0200502 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200505}
506
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512 int err;
513
514 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
Szymon Janc4e51eae2011-02-25 19:05:48 +0100521 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200522 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
Andre Guedes8c156c32011-07-07 10:30:36 -0300525 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 if (err < 0)
534 goto failed;
535
Johan Hedbergc542a062011-01-26 13:11:03 +0200536 ev.val = cp->val;
537
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539
540failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300541 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 hci_dev_put(hdev);
543
544 return err;
545}
546
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547#define EIR_FLAGS 0x01 /* flags */
548#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
549#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
550#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
551#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
552#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
553#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
554#define EIR_NAME_SHORT 0x08 /* shortened local name */
555#define EIR_NAME_COMPLETE 0x09 /* complete local name */
556#define EIR_TX_POWER 0x0A /* transmit power level */
557#define EIR_DEVICE_ID 0x10 /* device ID */
558
559#define PNP_INFO_SVCLASS_ID 0x1200
560
561static u8 bluetooth_base_uuid[] = {
562 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564};
565
566static u16 get_uuid16(u8 *uuid128)
567{
568 u32 val;
569 int i;
570
571 for (i = 0; i < 12; i++) {
572 if (bluetooth_base_uuid[i] != uuid128[i])
573 return 0;
574 }
575
576 memcpy(&val, &uuid128[12], 4);
577
578 val = le32_to_cpu(val);
579 if (val > 0xffff)
580 return 0;
581
582 return (u16) val;
583}
584
585static void create_eir(struct hci_dev *hdev, u8 *data)
586{
587 u8 *ptr = data;
588 u16 eir_len = 0;
589 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
590 int i, truncated = 0;
591 struct list_head *p;
592 size_t name_len;
593
594 name_len = strlen(hdev->dev_name);
595
596 if (name_len > 0) {
597 /* EIR Data type */
598 if (name_len > 48) {
599 name_len = 48;
600 ptr[1] = EIR_NAME_SHORT;
601 } else
602 ptr[1] = EIR_NAME_COMPLETE;
603
604 /* EIR Data length */
605 ptr[0] = name_len + 1;
606
607 memcpy(ptr + 2, hdev->dev_name, name_len);
608
609 eir_len += (name_len + 2);
610 ptr += (name_len + 2);
611 }
612
613 memset(uuid16_list, 0, sizeof(uuid16_list));
614
615 /* Group all UUID16 types */
616 list_for_each(p, &hdev->uuids) {
617 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
618 u16 uuid16;
619
620 uuid16 = get_uuid16(uuid->uuid);
621 if (uuid16 == 0)
622 return;
623
624 if (uuid16 < 0x1100)
625 continue;
626
627 if (uuid16 == PNP_INFO_SVCLASS_ID)
628 continue;
629
630 /* Stop if not enough space to put next UUID */
631 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
632 truncated = 1;
633 break;
634 }
635
636 /* Check for duplicates */
637 for (i = 0; uuid16_list[i] != 0; i++)
638 if (uuid16_list[i] == uuid16)
639 break;
640
641 if (uuid16_list[i] == 0) {
642 uuid16_list[i] = uuid16;
643 eir_len += sizeof(u16);
644 }
645 }
646
647 if (uuid16_list[0] != 0) {
648 u8 *length = ptr;
649
650 /* EIR Data type */
651 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
652
653 ptr += 2;
654 eir_len += 2;
655
656 for (i = 0; uuid16_list[i] != 0; i++) {
657 *ptr++ = (uuid16_list[i] & 0x00ff);
658 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
659 }
660
661 /* EIR Data length */
662 *length = (i * sizeof(u16)) + 1;
663 }
664}
665
666static int update_eir(struct hci_dev *hdev)
667{
668 struct hci_cp_write_eir cp;
669
670 if (!(hdev->features[6] & LMP_EXT_INQ))
671 return 0;
672
673 if (hdev->ssp_mode == 0)
674 return 0;
675
676 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
677 return 0;
678
679 memset(&cp, 0, sizeof(cp));
680
681 create_eir(hdev, cp.data);
682
683 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
684 return 0;
685
686 memcpy(hdev->eir, cp.data, sizeof(cp.data));
687
688 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
689}
690
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200691static u8 get_service_classes(struct hci_dev *hdev)
692{
693 struct list_head *p;
694 u8 val = 0;
695
696 list_for_each(p, &hdev->uuids) {
697 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
698
699 val |= uuid->svc_hint;
700 }
701
702 return val;
703}
704
705static int update_class(struct hci_dev *hdev)
706{
707 u8 cod[3];
708
709 BT_DBG("%s", hdev->name);
710
711 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
712 return 0;
713
714 cod[0] = hdev->minor_class;
715 cod[1] = hdev->major_class;
716 cod[2] = get_service_classes(hdev);
717
718 if (memcmp(cod, hdev->dev_class, 3) == 0)
719 return 0;
720
721 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
722}
723
Szymon Janc4e51eae2011-02-25 19:05:48 +0100724static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725{
726 struct mgmt_cp_add_uuid *cp;
727 struct hci_dev *hdev;
728 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729 int err;
730
731 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200732
Szymon Janc4e51eae2011-02-25 19:05:48 +0100733 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100735 if (len != sizeof(*cp))
736 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741
Andre Guedes8c156c32011-07-07 10:30:36 -0300742 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743
744 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
745 if (!uuid) {
746 err = -ENOMEM;
747 goto failed;
748 }
749
750 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200751 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200752
753 list_add(&uuid->list, &hdev->uuids);
754
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755 err = update_class(hdev);
756 if (err < 0)
757 goto failed;
758
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300759 err = update_eir(hdev);
760 if (err < 0)
761 goto failed;
762
Szymon Janc4e51eae2011-02-25 19:05:48 +0100763 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200764
765failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300766 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200767 hci_dev_put(hdev);
768
769 return err;
770}
771
Szymon Janc4e51eae2011-02-25 19:05:48 +0100772static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200773{
774 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100775 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200776 struct hci_dev *hdev;
777 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778 int err, found;
779
780 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781
Szymon Janc4e51eae2011-02-25 19:05:48 +0100782 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100784 if (len != sizeof(*cp))
785 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
786
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100789 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790
Andre Guedes8c156c32011-07-07 10:30:36 -0300791 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792
793 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
794 err = hci_uuids_clear(hdev);
795 goto unlock;
796 }
797
798 found = 0;
799
800 list_for_each_safe(p, n, &hdev->uuids) {
801 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
802
803 if (memcmp(match->uuid, cp->uuid, 16) != 0)
804 continue;
805
806 list_del(&match->list);
807 found++;
808 }
809
810 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200812 goto unlock;
813 }
814
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200815 err = update_class(hdev);
816 if (err < 0)
817 goto unlock;
818
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300819 err = update_eir(hdev);
820 if (err < 0)
821 goto unlock;
822
Szymon Janc4e51eae2011-02-25 19:05:48 +0100823 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200824
825unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300826 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200827 hci_dev_put(hdev);
828
829 return err;
830}
831
Szymon Janc4e51eae2011-02-25 19:05:48 +0100832static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
833 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200834{
835 struct hci_dev *hdev;
836 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200837 int err;
838
839 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100843 if (len != sizeof(*cp))
844 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
845
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849
Andre Guedes8c156c32011-07-07 10:30:36 -0300850 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851
852 hdev->major_class = cp->major;
853 hdev->minor_class = cp->minor;
854
855 err = update_class(hdev);
856
857 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100858 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200859
Andre Guedes8c156c32011-07-07 10:30:36 -0300860 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861 hci_dev_put(hdev);
862
863 return err;
864}
865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
867 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200868{
869 struct hci_dev *hdev;
870 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200871 int err;
872
873 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200874
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100875 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100876 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100877
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
Andre Guedes8c156c32011-07-07 10:30:36 -0300882 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
886 if (cp->enable) {
887 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
888 err = 0;
889 } else {
890 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
891 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300892 if (err == 0)
893 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200894 }
895
896 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100897 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
898 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899
Andre Guedes8c156c32011-07-07 10:30:36 -0300900 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200901 hci_dev_put(hdev);
902
903 return err;
904}
905
Szymon Janc4e51eae2011-02-25 19:05:48 +0100906static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200907{
908 struct hci_dev *hdev;
909 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300911 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200912
913 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100914
915 if (len < sizeof(*cp))
916 return -EINVAL;
917
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200918 key_count = get_unaligned_le16(&cp->key_count);
919
920 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300921 if (expected_len != len) {
922 BT_ERR("load_keys: expected %u bytes, got %u bytes",
923 len, expected_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200924 return -EINVAL;
925 }
926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200930
Szymon Janc4e51eae2011-02-25 19:05:48 +0100931 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200932 key_count);
933
Andre Guedes8c156c32011-07-07 10:30:36 -0300934 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935
936 hci_link_keys_clear(hdev);
937
938 set_bit(HCI_LINK_KEYS, &hdev->flags);
939
940 if (cp->debug_keys)
941 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
942 else
943 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
944
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300945 for (i = 0; i < key_count; i++) {
946 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200947
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
Andre Guedes8c156c32011-07-07 10:30:36 -0300952 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200953 hci_dev_put(hdev);
954
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300955 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200956}
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
Andre Guedes8c156c32011-07-07 10:30:36 -0300974 hci_dev_lock_bh(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 */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400993 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200994 }
995
996unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300997 hci_dev_unlock_bh(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
Andre Guedes8c156c32011-07-07 10:30:36 -03001023 hci_dev_lock_bh(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:
Andre Guedes8c156c32011-07-07 10:30:36 -03001058 hci_dev_unlock_bh(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
Andre Guedes8c156c32011-07-07 10:30:36 -03001079 hci_dev_lock_bh(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);
Andre Guedes8c156c32011-07-07 10:30:36 -03001106 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107 hci_dev_put(hdev);
1108 return err;
1109}
1110
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001111static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1112 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1113{
1114 struct pending_cmd *cmd;
1115 int err;
1116
1117 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1118 sizeof(*cp));
1119 if (!cmd)
1120 return -ENOMEM;
1121
1122 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1123 &cp->bdaddr);
1124 if (err < 0)
1125 mgmt_pending_remove(cmd);
1126
1127 return err;
1128}
1129
Szymon Janc4e51eae2011-02-25 19:05:48 +01001130static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1131 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001132{
1133 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001134 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001135 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001136 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001137 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001138 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001139 int err;
1140
1141 BT_DBG("");
1142
1143 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001144
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001145 if (len != sizeof(*cp))
1146 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1147
Szymon Janc4e51eae2011-02-25 19:05:48 +01001148 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001149 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001150 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001151
Andre Guedes8c156c32011-07-07 10:30:36 -03001152 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001153
1154 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001155 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001156 goto failed;
1157 }
1158
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001159 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1160 if (!conn) {
1161 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1162 goto failed;
1163 }
1164
1165 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1166 bacpy(&ncp.bdaddr, &cp->bdaddr);
1167
1168 BT_ERR("PIN code is not 16 bytes long");
1169
1170 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1171 if (err >= 0)
1172 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1173 EINVAL);
1174
1175 goto failed;
1176 }
1177
Szymon Janc4e51eae2011-02-25 19:05:48 +01001178 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001179 if (!cmd) {
1180 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001181 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001182 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001183
1184 bacpy(&reply.bdaddr, &cp->bdaddr);
1185 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001186 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001187
1188 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1189 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001190 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001191
1192failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001193 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001194 hci_dev_put(hdev);
1195
1196 return err;
1197}
1198
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1200 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001201{
1202 struct hci_dev *hdev;
1203 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001204 int err;
1205
1206 BT_DBG("");
1207
1208 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001209
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001210 if (len != sizeof(*cp))
1211 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1212 EINVAL);
1213
Szymon Janc4e51eae2011-02-25 19:05:48 +01001214 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001216 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1217 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001218
Andre Guedes8c156c32011-07-07 10:30:36 -03001219 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001220
1221 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001222 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1223 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224 goto failed;
1225 }
1226
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001227 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228
1229failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001230 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001231 hci_dev_put(hdev);
1232
1233 return err;
1234}
1235
Szymon Janc4e51eae2011-02-25 19:05:48 +01001236static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1237 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001238{
1239 struct hci_dev *hdev;
1240 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001241
1242 BT_DBG("");
1243
1244 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001245
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001246 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001247 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001248
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001250 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001251 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001252
Andre Guedes8c156c32011-07-07 10:30:36 -03001253 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001254
1255 hdev->io_capability = cp->io_capability;
1256
1257 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001258 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001259
Andre Guedes8c156c32011-07-07 10:30:36 -03001260 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001261 hci_dev_put(hdev);
1262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001264}
1265
Johan Hedberge9a416b2011-02-19 12:05:56 -03001266static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1267{
1268 struct hci_dev *hdev = conn->hdev;
1269 struct list_head *p;
1270
1271 list_for_each(p, &cmd_list) {
1272 struct pending_cmd *cmd;
1273
1274 cmd = list_entry(p, struct pending_cmd, list);
1275
1276 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1277 continue;
1278
1279 if (cmd->index != hdev->id)
1280 continue;
1281
1282 if (cmd->user_data != conn)
1283 continue;
1284
1285 return cmd;
1286 }
1287
1288 return NULL;
1289}
1290
1291static void pairing_complete(struct pending_cmd *cmd, u8 status)
1292{
1293 struct mgmt_rp_pair_device rp;
1294 struct hci_conn *conn = cmd->user_data;
1295
Johan Hedberge9a416b2011-02-19 12:05:56 -03001296 bacpy(&rp.bdaddr, &conn->dst);
1297 rp.status = status;
1298
Szymon Janc4e51eae2011-02-25 19:05:48 +01001299 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001300
1301 /* So we don't get further callbacks for this connection */
1302 conn->connect_cfm_cb = NULL;
1303 conn->security_cfm_cb = NULL;
1304 conn->disconn_cfm_cb = NULL;
1305
1306 hci_conn_put(conn);
1307
Johan Hedberga664b5b2011-02-19 12:06:02 -03001308 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001309}
1310
1311static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1312{
1313 struct pending_cmd *cmd;
1314
1315 BT_DBG("status %u", status);
1316
1317 cmd = find_pairing(conn);
1318 if (!cmd) {
1319 BT_DBG("Unable to find a pending command");
1320 return;
1321 }
1322
1323 pairing_complete(cmd, status);
1324}
1325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001327{
1328 struct hci_dev *hdev;
1329 struct mgmt_cp_pair_device *cp;
1330 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001331 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001332 u8 sec_level, auth_type;
1333 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001334 int err;
1335
1336 BT_DBG("");
1337
1338 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001339
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001340 if (len != sizeof(*cp))
1341 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1342
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001344 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001346
Andre Guedes8c156c32011-07-07 10:30:36 -03001347 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001348
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001349 sec_level = BT_SECURITY_MEDIUM;
1350 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001351 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001352 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001353 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001354
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001355 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1356 if (entry)
1357 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1358 auth_type);
1359 else
1360 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1361 auth_type);
1362
Ville Tervo30e76272011-02-22 16:10:53 -03001363 if (IS_ERR(conn)) {
1364 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365 goto unlock;
1366 }
1367
1368 if (conn->connect_cfm_cb) {
1369 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001370 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001371 goto unlock;
1372 }
1373
Szymon Janc4e51eae2011-02-25 19:05:48 +01001374 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 if (!cmd) {
1376 err = -ENOMEM;
1377 hci_conn_put(conn);
1378 goto unlock;
1379 }
1380
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001381 /* For LE, just connecting isn't a proof that the pairing finished */
1382 if (!entry)
1383 conn->connect_cfm_cb = pairing_complete_cb;
1384
Johan Hedberge9a416b2011-02-19 12:05:56 -03001385 conn->security_cfm_cb = pairing_complete_cb;
1386 conn->disconn_cfm_cb = pairing_complete_cb;
1387 conn->io_capability = cp->io_cap;
1388 cmd->user_data = conn;
1389
1390 if (conn->state == BT_CONNECTED &&
1391 hci_conn_security(conn, sec_level, auth_type))
1392 pairing_complete(cmd, 0);
1393
1394 err = 0;
1395
1396unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001397 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001398 hci_dev_put(hdev);
1399
1400 return err;
1401}
1402
Szymon Janc4e51eae2011-02-25 19:05:48 +01001403static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1404 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001405{
1406 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001408 struct pending_cmd *cmd;
1409 struct hci_dev *hdev;
1410 int err;
1411
1412 BT_DBG("");
1413
Johan Hedberga5c29682011-02-19 12:05:57 -03001414 if (success) {
1415 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1416 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1417 } else {
1418 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1419 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1420 }
1421
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001422 if (len != sizeof(*cp))
1423 return cmd_status(sk, index, mgmt_op, EINVAL);
1424
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001426 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001428
Andre Guedes8c156c32011-07-07 10:30:36 -03001429 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001430
Johan Hedberga5c29682011-02-19 12:05:57 -03001431 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001432 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001433 goto failed;
1434 }
1435
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001437 if (!cmd) {
1438 err = -ENOMEM;
1439 goto failed;
1440 }
1441
1442 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001443 if (err < 0)
1444 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001445
1446failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001447 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001448 hci_dev_put(hdev);
1449
1450 return err;
1451}
1452
Johan Hedbergb312b1612011-03-16 14:29:37 +02001453static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1454 u16 len)
1455{
1456 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1457 struct hci_cp_write_local_name hci_cp;
1458 struct hci_dev *hdev;
1459 struct pending_cmd *cmd;
1460 int err;
1461
1462 BT_DBG("");
1463
1464 if (len != sizeof(*mgmt_cp))
1465 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1466
1467 hdev = hci_dev_get(index);
1468 if (!hdev)
1469 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1470
Andre Guedes8c156c32011-07-07 10:30:36 -03001471 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001472
1473 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1474 if (!cmd) {
1475 err = -ENOMEM;
1476 goto failed;
1477 }
1478
1479 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1480 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1481 &hci_cp);
1482 if (err < 0)
1483 mgmt_pending_remove(cmd);
1484
1485failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001486 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001487 hci_dev_put(hdev);
1488
1489 return err;
1490}
1491
Szymon Jancc35938b2011-03-22 13:12:21 +01001492static int read_local_oob_data(struct sock *sk, u16 index)
1493{
1494 struct hci_dev *hdev;
1495 struct pending_cmd *cmd;
1496 int err;
1497
1498 BT_DBG("hci%u", index);
1499
1500 hdev = hci_dev_get(index);
1501 if (!hdev)
1502 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1503 ENODEV);
1504
Andre Guedes8c156c32011-07-07 10:30:36 -03001505 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001506
1507 if (!test_bit(HCI_UP, &hdev->flags)) {
1508 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1509 ENETDOWN);
1510 goto unlock;
1511 }
1512
1513 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1514 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1515 EOPNOTSUPP);
1516 goto unlock;
1517 }
1518
1519 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1520 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1521 goto unlock;
1522 }
1523
1524 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1525 if (!cmd) {
1526 err = -ENOMEM;
1527 goto unlock;
1528 }
1529
1530 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1531 if (err < 0)
1532 mgmt_pending_remove(cmd);
1533
1534unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001535 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001536 hci_dev_put(hdev);
1537
1538 return err;
1539}
1540
Szymon Janc2763eda2011-03-22 13:12:22 +01001541static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1542 u16 len)
1543{
1544 struct hci_dev *hdev;
1545 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1546 int err;
1547
1548 BT_DBG("hci%u ", index);
1549
1550 if (len != sizeof(*cp))
1551 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1552 EINVAL);
1553
1554 hdev = hci_dev_get(index);
1555 if (!hdev)
1556 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1557 ENODEV);
1558
Andre Guedes8c156c32011-07-07 10:30:36 -03001559 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001560
1561 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1562 cp->randomizer);
1563 if (err < 0)
1564 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1565 else
1566 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1567 0);
1568
Andre Guedes8c156c32011-07-07 10:30:36 -03001569 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001570 hci_dev_put(hdev);
1571
1572 return err;
1573}
1574
1575static int remove_remote_oob_data(struct sock *sk, u16 index,
1576 unsigned char *data, u16 len)
1577{
1578 struct hci_dev *hdev;
1579 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1580 int err;
1581
1582 BT_DBG("hci%u ", index);
1583
1584 if (len != sizeof(*cp))
1585 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1586 EINVAL);
1587
1588 hdev = hci_dev_get(index);
1589 if (!hdev)
1590 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1591 ENODEV);
1592
Andre Guedes8c156c32011-07-07 10:30:36 -03001593 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001594
1595 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1596 if (err < 0)
1597 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1598 -err);
1599 else
1600 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1601 NULL, 0);
1602
Andre Guedes8c156c32011-07-07 10:30:36 -03001603 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001604 hci_dev_put(hdev);
1605
1606 return err;
1607}
1608
Johan Hedberg14a53662011-04-27 10:29:56 -04001609static int start_discovery(struct sock *sk, u16 index)
1610{
1611 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1612 struct hci_cp_inquiry cp;
1613 struct pending_cmd *cmd;
1614 struct hci_dev *hdev;
1615 int err;
1616
1617 BT_DBG("hci%u", index);
1618
1619 hdev = hci_dev_get(index);
1620 if (!hdev)
1621 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1622
1623 hci_dev_lock_bh(hdev);
1624
1625 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1626 if (!cmd) {
1627 err = -ENOMEM;
1628 goto failed;
1629 }
1630
1631 memset(&cp, 0, sizeof(cp));
1632 memcpy(&cp.lap, lap, 3);
1633 cp.length = 0x08;
1634 cp.num_rsp = 0x00;
1635
1636 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1637 if (err < 0)
1638 mgmt_pending_remove(cmd);
1639
1640failed:
1641 hci_dev_unlock_bh(hdev);
1642 hci_dev_put(hdev);
1643
1644 return err;
1645}
1646
1647static int stop_discovery(struct sock *sk, u16 index)
1648{
1649 struct hci_dev *hdev;
1650 struct pending_cmd *cmd;
1651 int err;
1652
1653 BT_DBG("hci%u", index);
1654
1655 hdev = hci_dev_get(index);
1656 if (!hdev)
1657 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1658
1659 hci_dev_lock_bh(hdev);
1660
1661 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1662 if (!cmd) {
1663 err = -ENOMEM;
1664 goto failed;
1665 }
1666
1667 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1668 if (err < 0)
1669 mgmt_pending_remove(cmd);
1670
1671failed:
1672 hci_dev_unlock_bh(hdev);
1673 hci_dev_put(hdev);
1674
1675 return err;
1676}
1677
Antti Julku7fbec222011-06-15 12:01:15 +03001678static int block_device(struct sock *sk, u16 index, unsigned char *data,
1679 u16 len)
1680{
1681 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001682 struct pending_cmd *cmd;
1683 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001684 int err;
1685
1686 BT_DBG("hci%u", index);
1687
Antti Julku7fbec222011-06-15 12:01:15 +03001688 if (len != sizeof(*cp))
1689 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1690 EINVAL);
1691
1692 hdev = hci_dev_get(index);
1693 if (!hdev)
1694 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1695 ENODEV);
1696
Antti Julku5e762442011-08-25 16:48:02 +03001697 hci_dev_lock_bh(hdev);
1698
1699 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1700 if (!cmd) {
1701 err = -ENOMEM;
1702 goto failed;
1703 }
1704
Antti Julku7fbec222011-06-15 12:01:15 +03001705 err = hci_blacklist_add(hdev, &cp->bdaddr);
1706
1707 if (err < 0)
1708 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1709 else
1710 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1711 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001712
1713 mgmt_pending_remove(cmd);
1714
1715failed:
1716 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001717 hci_dev_put(hdev);
1718
1719 return err;
1720}
1721
1722static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1723 u16 len)
1724{
1725 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001726 struct pending_cmd *cmd;
1727 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001728 int err;
1729
1730 BT_DBG("hci%u", index);
1731
Antti Julku7fbec222011-06-15 12:01:15 +03001732 if (len != sizeof(*cp))
1733 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1734 EINVAL);
1735
1736 hdev = hci_dev_get(index);
1737 if (!hdev)
1738 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1739 ENODEV);
1740
Antti Julku5e762442011-08-25 16:48:02 +03001741 hci_dev_lock_bh(hdev);
1742
1743 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1744 if (!cmd) {
1745 err = -ENOMEM;
1746 goto failed;
1747 }
1748
Antti Julku7fbec222011-06-15 12:01:15 +03001749 err = hci_blacklist_del(hdev, &cp->bdaddr);
1750
1751 if (err < 0)
1752 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1753 else
1754 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1755 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001756
1757 mgmt_pending_remove(cmd);
1758
1759failed:
1760 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001761 hci_dev_put(hdev);
1762
1763 return err;
1764}
1765
Antti Julkuf6422ec2011-06-22 13:11:56 +03001766static int set_fast_connectable(struct sock *sk, u16 index,
1767 unsigned char *data, u16 len)
1768{
1769 struct hci_dev *hdev;
1770 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1771 struct hci_cp_write_page_scan_activity acp;
1772 u8 type;
1773 int err;
1774
1775 BT_DBG("hci%u", index);
1776
1777 if (len != sizeof(*cp))
1778 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1779 EINVAL);
1780
1781 hdev = hci_dev_get(index);
1782 if (!hdev)
1783 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1784 ENODEV);
1785
1786 hci_dev_lock(hdev);
1787
1788 if (cp->enable) {
1789 type = PAGE_SCAN_TYPE_INTERLACED;
1790 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1791 } else {
1792 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1793 acp.interval = 0x0800; /* default 1.28 sec page scan */
1794 }
1795
1796 acp.window = 0x0012; /* default 11.25 msec page scan window */
1797
1798 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1799 sizeof(acp), &acp);
1800 if (err < 0) {
1801 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1802 -err);
1803 goto done;
1804 }
1805
1806 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1807 if (err < 0) {
1808 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1809 -err);
1810 goto done;
1811 }
1812
1813 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1814 NULL, 0);
1815done:
1816 hci_dev_unlock(hdev);
1817 hci_dev_put(hdev);
1818
1819 return err;
1820}
1821
Johan Hedberg03811012010-12-08 00:21:06 +02001822int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1823{
1824 unsigned char *buf;
1825 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001826 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001827 int err;
1828
1829 BT_DBG("got %zu bytes", msglen);
1830
1831 if (msglen < sizeof(*hdr))
1832 return -EINVAL;
1833
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001834 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001835 if (!buf)
1836 return -ENOMEM;
1837
1838 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1839 err = -EFAULT;
1840 goto done;
1841 }
1842
1843 hdr = (struct mgmt_hdr *) buf;
1844 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001846 len = get_unaligned_le16(&hdr->len);
1847
1848 if (len != msglen - sizeof(*hdr)) {
1849 err = -EINVAL;
1850 goto done;
1851 }
1852
1853 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001854 case MGMT_OP_READ_VERSION:
1855 err = read_version(sk);
1856 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001857 case MGMT_OP_READ_INDEX_LIST:
1858 err = read_index_list(sk);
1859 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001860 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001861 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001862 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001863 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001865 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001866 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001867 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001868 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001869 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001870 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001871 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001872 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001874 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001875 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001877 break;
1878 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001879 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001880 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001881 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001882 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001883 break;
1884 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001886 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001887 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889 break;
1890 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001893 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001895 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001896 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001897 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001898 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001899 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001900 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001901 break;
1902 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001903 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001904 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001905 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001906 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001909 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001911 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001912 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001913 break;
1914 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001915 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001916 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001917 case MGMT_OP_SET_LOCAL_NAME:
1918 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1919 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001920 case MGMT_OP_READ_LOCAL_OOB_DATA:
1921 err = read_local_oob_data(sk, index);
1922 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001923 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1924 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1925 break;
1926 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1927 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1928 len);
1929 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001930 case MGMT_OP_START_DISCOVERY:
1931 err = start_discovery(sk, index);
1932 break;
1933 case MGMT_OP_STOP_DISCOVERY:
1934 err = stop_discovery(sk, index);
1935 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001936 case MGMT_OP_BLOCK_DEVICE:
1937 err = block_device(sk, index, buf + sizeof(*hdr), len);
1938 break;
1939 case MGMT_OP_UNBLOCK_DEVICE:
1940 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1941 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001942 case MGMT_OP_SET_FAST_CONNECTABLE:
1943 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1944 len);
1945 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001946 default:
1947 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001948 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001949 break;
1950 }
1951
Johan Hedberge41d8b42010-12-13 21:07:03 +02001952 if (err < 0)
1953 goto done;
1954
Johan Hedberg03811012010-12-08 00:21:06 +02001955 err = msglen;
1956
1957done:
1958 kfree(buf);
1959 return err;
1960}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001961
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001962int mgmt_index_added(u16 index)
1963{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001964 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001965}
1966
1967int mgmt_index_removed(u16 index)
1968{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001969 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001970}
1971
Johan Hedberg73f22f62010-12-29 16:00:25 +02001972struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001973 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001974 struct sock *sk;
1975};
1976
Johan Hedberg72a734e2010-12-30 00:38:22 +02001977static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001979 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001980 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001981
Johan Hedberg72a734e2010-12-30 00:38:22 +02001982 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001983 return;
1984
Johan Hedberg053f0212011-01-26 13:07:10 +02001985 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001986
1987 list_del(&cmd->list);
1988
1989 if (match->sk == NULL) {
1990 match->sk = cmd->sk;
1991 sock_hold(match->sk);
1992 }
1993
1994 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001995}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001996
1997int mgmt_powered(u16 index, u8 powered)
1998{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001999 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002000 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002001 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002002
Johan Hedberg72a734e2010-12-30 00:38:22 +02002003 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002004
Johan Hedberg72a734e2010-12-30 00:38:22 +02002005 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002006
Szymon Janc4e51eae2011-02-25 19:05:48 +01002007 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002008
2009 if (match.sk)
2010 sock_put(match.sk);
2011
2012 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002013}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002014
Johan Hedberg73f22f62010-12-29 16:00:25 +02002015int mgmt_discoverable(u16 index, u8 discoverable)
2016{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002017 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002018 struct cmd_lookup match = { discoverable, NULL };
2019 int ret;
2020
Szymon Jancb8534e02011-03-01 16:55:34 +01002021 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002022
Johan Hedberg72a734e2010-12-30 00:38:22 +02002023 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002024
Szymon Janc4e51eae2011-02-25 19:05:48 +01002025 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2026 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002027
2028 if (match.sk)
2029 sock_put(match.sk);
2030
2031 return ret;
2032}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002033
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002034int mgmt_connectable(u16 index, u8 connectable)
2035{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002037 struct cmd_lookup match = { connectable, NULL };
2038 int ret;
2039
Johan Hedberg72a734e2010-12-30 00:38:22 +02002040 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002041
Johan Hedberg72a734e2010-12-30 00:38:22 +02002042 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002043
Szymon Janc4e51eae2011-02-25 19:05:48 +01002044 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002045
2046 if (match.sk)
2047 sock_put(match.sk);
2048
2049 return ret;
2050}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002051
Johan Hedberg4df378a2011-04-28 11:29:03 -07002052int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002053{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002054 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002055
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002056 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002057
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002058 ev.store_hint = persistent;
2059 bacpy(&ev.key.bdaddr, &key->bdaddr);
2060 ev.key.type = key->type;
2061 memcpy(ev.key.val, key->val, 16);
2062 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002063
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002064 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002065}
Johan Hedbergf7520542011-01-20 12:34:39 +02002066
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002067int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002068{
2069 struct mgmt_ev_connected ev;
2070
Johan Hedbergf7520542011-01-20 12:34:39 +02002071 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002072 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002073
Szymon Janc4e51eae2011-02-25 19:05:48 +01002074 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002075}
2076
Johan Hedberg8962ee72011-01-20 12:40:27 +02002077static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2078{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002079 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002080 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002081 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002082
Johan Hedberga38528f2011-01-22 06:46:43 +02002083 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084
Szymon Janc4e51eae2011-02-25 19:05:48 +01002085 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002086
2087 *sk = cmd->sk;
2088 sock_hold(*sk);
2089
Johan Hedberga664b5b2011-02-19 12:06:02 -03002090 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091}
2092
Johan Hedbergf7520542011-01-20 12:34:39 +02002093int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2094{
2095 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002096 struct sock *sk = NULL;
2097 int err;
2098
2099 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002100
Johan Hedbergf7520542011-01-20 12:34:39 +02002101 bacpy(&ev.bdaddr, bdaddr);
2102
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002104
2105 if (sk)
2106 sock_put(sk);
2107
2108 return err;
2109}
2110
2111int mgmt_disconnect_failed(u16 index)
2112{
2113 struct pending_cmd *cmd;
2114 int err;
2115
2116 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2117 if (!cmd)
2118 return -ENOENT;
2119
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002121
Johan Hedberga664b5b2011-02-19 12:06:02 -03002122 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123
2124 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002125}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002126
2127int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2128{
2129 struct mgmt_ev_connect_failed ev;
2130
Johan Hedberg17d5c042011-01-22 06:09:08 +02002131 bacpy(&ev.bdaddr, bdaddr);
2132 ev.status = status;
2133
Szymon Janc4e51eae2011-02-25 19:05:48 +01002134 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002135}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002136
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002137int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138{
2139 struct mgmt_ev_pin_code_request ev;
2140
Johan Hedberg980e1a52011-01-22 06:10:07 +02002141 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002142 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143
Szymon Janc4e51eae2011-02-25 19:05:48 +01002144 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2145 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146}
2147
2148int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2149{
2150 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002151 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002152 int err;
2153
2154 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2155 if (!cmd)
2156 return -ENOENT;
2157
Johan Hedbergac56fb12011-02-19 12:05:59 -03002158 bacpy(&rp.bdaddr, bdaddr);
2159 rp.status = status;
2160
Szymon Janc4e51eae2011-02-25 19:05:48 +01002161 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2162 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002163
Johan Hedberga664b5b2011-02-19 12:06:02 -03002164 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002165
2166 return err;
2167}
2168
2169int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2170{
2171 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002172 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002173 int err;
2174
2175 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2176 if (!cmd)
2177 return -ENOENT;
2178
Johan Hedbergac56fb12011-02-19 12:05:59 -03002179 bacpy(&rp.bdaddr, bdaddr);
2180 rp.status = status;
2181
Szymon Janc4e51eae2011-02-25 19:05:48 +01002182 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2183 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184
Johan Hedberga664b5b2011-02-19 12:06:02 -03002185 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186
2187 return err;
2188}
Johan Hedberga5c29682011-02-19 12:05:57 -03002189
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002190int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2191 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002192{
2193 struct mgmt_ev_user_confirm_request ev;
2194
2195 BT_DBG("hci%u", index);
2196
Johan Hedberga5c29682011-02-19 12:05:57 -03002197 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002198 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002199 put_unaligned_le32(value, &ev.value);
2200
Szymon Janc4e51eae2011-02-25 19:05:48 +01002201 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2202 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002203}
2204
2205static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2206 u8 opcode)
2207{
2208 struct pending_cmd *cmd;
2209 struct mgmt_rp_user_confirm_reply rp;
2210 int err;
2211
2212 cmd = mgmt_pending_find(opcode, index);
2213 if (!cmd)
2214 return -ENOENT;
2215
Johan Hedberga5c29682011-02-19 12:05:57 -03002216 bacpy(&rp.bdaddr, bdaddr);
2217 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002218 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002219
Johan Hedberga664b5b2011-02-19 12:06:02 -03002220 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002221
2222 return err;
2223}
2224
2225int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2226{
2227 return confirm_reply_complete(index, bdaddr, status,
2228 MGMT_OP_USER_CONFIRM_REPLY);
2229}
2230
Szymon Jancb8534e02011-03-01 16:55:34 +01002231int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002232{
2233 return confirm_reply_complete(index, bdaddr, status,
2234 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2235}
Johan Hedberg2a611692011-02-19 12:06:00 -03002236
2237int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2238{
2239 struct mgmt_ev_auth_failed ev;
2240
Johan Hedberg2a611692011-02-19 12:06:00 -03002241 bacpy(&ev.bdaddr, bdaddr);
2242 ev.status = status;
2243
Szymon Janc4e51eae2011-02-25 19:05:48 +01002244 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002245}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002246
2247int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2248{
2249 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002250 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002251 struct mgmt_cp_set_local_name ev;
2252 int err;
2253
2254 memset(&ev, 0, sizeof(ev));
2255 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2256
2257 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2258 if (!cmd)
2259 goto send_event;
2260
2261 if (status) {
2262 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2263 goto failed;
2264 }
2265
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002266 hdev = hci_dev_get(index);
2267 if (hdev) {
2268 hci_dev_lock_bh(hdev);
2269 update_eir(hdev);
2270 hci_dev_unlock_bh(hdev);
2271 hci_dev_put(hdev);
2272 }
2273
Johan Hedbergb312b1612011-03-16 14:29:37 +02002274 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2275 sizeof(ev));
2276 if (err < 0)
2277 goto failed;
2278
2279send_event:
2280 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2281 cmd ? cmd->sk : NULL);
2282
2283failed:
2284 if (cmd)
2285 mgmt_pending_remove(cmd);
2286 return err;
2287}
Szymon Jancc35938b2011-03-22 13:12:21 +01002288
2289int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2290 u8 status)
2291{
2292 struct pending_cmd *cmd;
2293 int err;
2294
2295 BT_DBG("hci%u status %u", index, status);
2296
2297 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2298 if (!cmd)
2299 return -ENOENT;
2300
2301 if (status) {
2302 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2303 EIO);
2304 } else {
2305 struct mgmt_rp_read_local_oob_data rp;
2306
2307 memcpy(rp.hash, hash, sizeof(rp.hash));
2308 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2309
2310 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2311 &rp, sizeof(rp));
2312 }
2313
2314 mgmt_pending_remove(cmd);
2315
2316 return err;
2317}
Johan Hedberge17acd42011-03-30 23:57:16 +03002318
2319int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2320 u8 *eir)
2321{
2322 struct mgmt_ev_device_found ev;
2323
2324 memset(&ev, 0, sizeof(ev));
2325
2326 bacpy(&ev.bdaddr, bdaddr);
2327 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2328 ev.rssi = rssi;
2329
2330 if (eir)
2331 memcpy(ev.eir, eir, sizeof(ev.eir));
2332
2333 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2334}
Johan Hedberga88a9652011-03-30 13:18:12 +03002335
2336int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2337{
2338 struct mgmt_ev_remote_name ev;
2339
2340 memset(&ev, 0, sizeof(ev));
2341
2342 bacpy(&ev.bdaddr, bdaddr);
2343 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2344
2345 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2346}
Johan Hedberg314b2382011-04-27 10:29:57 -04002347
2348int mgmt_discovering(u16 index, u8 discovering)
2349{
2350 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2351 sizeof(discovering), NULL);
2352}
Antti Julku5e762442011-08-25 16:48:02 +03002353
2354int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2355{
2356 struct pending_cmd *cmd;
2357 struct mgmt_ev_device_blocked ev;
2358
2359 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2360
2361 bacpy(&ev.bdaddr, bdaddr);
2362
2363 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2364 cmd ? cmd->sk : NULL);
2365}
2366
2367int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2368{
2369 struct pending_cmd *cmd;
2370 struct mgmt_ev_device_unblocked ev;
2371
2372 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2373
2374 bacpy(&ev.bdaddr, bdaddr);
2375
2376 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2377 cmd ? cmd->sk : NULL);
2378}