blob: 16033bbde051be83b27aa0440d8e0cb051033720 [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>
Brian Gixa68668b2011-08-11 15:49:36 -070030#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020031#include <net/bluetooth/mgmt.h>
Brian Gixa68668b2011-08-11 15:49:36 -070032#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020033
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Brian Gixa68668b2011-08-11 15:49:36 -070037enum scan_mode {
38 SCAN_IDLE,
39 SCAN_LE,
40 SCAN_BR
41};
42
43struct disco_interleave {
44 struct timer_list timer;
45 struct timer_list le_timer;
46 u16 index;
47 enum scan_mode mode;
48 int int_phase;
49 int int_count;
50};
51
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020052struct pending_cmd {
53 struct list_head list;
54 __u16 opcode;
55 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010056 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030058 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020059};
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020062
Szymon Janc4e51eae2011-02-25 19:05:48 +010063static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020064{
65 struct sk_buff *skb;
66 struct mgmt_hdr *hdr;
67 struct mgmt_ev_cmd_status *ev;
68
Szymon Janc34eb5252011-02-28 14:10:08 +010069 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020070
71 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
72 if (!skb)
73 return -ENOMEM;
74
75 hdr = (void *) skb_put(skb, sizeof(*hdr));
76
77 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010078 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020079 hdr->len = cpu_to_le16(sizeof(*ev));
80
81 ev = (void *) skb_put(skb, sizeof(*ev));
82 ev->status = status;
83 put_unaligned_le16(cmd, &ev->opcode);
84
85 if (sock_queue_rcv_skb(sk, skb) < 0)
86 kfree_skb(skb);
87
88 return 0;
89}
90
Szymon Janc4e51eae2011-02-25 19:05:48 +010091static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
92 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020093{
94 struct sk_buff *skb;
95 struct mgmt_hdr *hdr;
96 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020097
98 BT_DBG("sock %p", sk);
99
Johan Hedberga38528f2011-01-22 06:46:43 +0200100 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101 if (!skb)
102 return -ENOMEM;
103
104 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200105
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100107 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200108 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200109
Johan Hedberga38528f2011-01-22 06:46:43 +0200110 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
111 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100112
113 if (rp)
114 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200115
116 if (sock_queue_rcv_skb(sk, skb) < 0)
117 kfree_skb(skb);
118
119 return 0;
120}
121
Johan Hedberga38528f2011-01-22 06:46:43 +0200122static int read_version(struct sock *sk)
123{
124 struct mgmt_rp_read_version rp;
125
126 BT_DBG("sock %p", sk);
127
128 rp.version = MGMT_VERSION;
129 put_unaligned_le16(MGMT_REVISION, &rp.revision);
130
Szymon Janc4e51eae2011-02-25 19:05:48 +0100131 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
132 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200133}
134
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135static int read_index_list(struct sock *sk)
136{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 struct mgmt_rp_read_index_list *rp;
138 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200139 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200141 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142
143 BT_DBG("sock %p", sk);
144
145 read_lock(&hci_dev_list_lock);
146
147 count = 0;
148 list_for_each(p, &hci_dev_list) {
149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200167 set_bit(HCI_MGMT, &d->flags);
168
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200169 if (test_bit(HCI_SETUP, &d->flags))
170 continue;
171
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200172 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700173 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200174 BT_DBG("Added hci%u", d->id);
175 }
176
177 read_unlock(&hci_dev_list_lock);
178
Szymon Janc4e51eae2011-02-25 19:05:48 +0100179 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
180 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200181
Johan Hedberga38528f2011-01-22 06:46:43 +0200182 kfree(rp);
183
184 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200185}
186
Szymon Janc4e51eae2011-02-25 19:05:48 +0100187static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200188{
Johan Hedberga38528f2011-01-22 06:46:43 +0200189 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200190 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200193
Szymon Janc4e51eae2011-02-25 19:05:48 +0100194 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200195 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200198 hci_del_off_timer(hdev);
199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200202 set_bit(HCI_MGMT, &hdev->flags);
203
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200204 memset(&rp, 0, sizeof(rp));
205
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207
Johan Hedberga38528f2011-01-22 06:46:43 +0200208 rp.powered = test_bit(HCI_UP, &hdev->flags);
209 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
210 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
211 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
213 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200216 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200218 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200219
Johan Hedberga38528f2011-01-22 06:46:43 +0200220 bacpy(&rp.bdaddr, &hdev->bdaddr);
221 memcpy(rp.features, hdev->features, 8);
222 memcpy(rp.dev_class, hdev->dev_class, 3);
223 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
224 rp.hci_ver = hdev->hci_ver;
225 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200227 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200230 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200231
Szymon Janc4e51eae2011-02-25 19:05:48 +0100232 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200233}
234
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200235static void mgmt_pending_free(struct pending_cmd *cmd)
236{
Brian Gixa68668b2011-08-11 15:49:36 -0700237 BT_DBG("%d", cmd->opcode);
238
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100240 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 kfree(cmd);
242}
243
Johan Hedberg366a0332011-02-19 12:05:55 -0300244static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
245 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200246{
247 struct pending_cmd *cmd;
248
Brian Gixa68668b2011-08-11 15:49:36 -0700249 BT_DBG("%d", opcode);
250
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200251 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
252 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300253 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200254
255 cmd->opcode = opcode;
256 cmd->index = index;
257
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100258 cmd->param = kmalloc(len, GFP_ATOMIC);
259 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200260 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300261 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200262 }
263
Szymon Janc8fce6352011-03-22 13:12:20 +0100264 if (data)
265 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200266
267 cmd->sk = sk;
268 sock_hold(sk);
269
270 list_add(&cmd->list, &cmd_list);
271
Johan Hedberg366a0332011-02-19 12:05:55 -0300272 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200273}
274
275static void mgmt_pending_foreach(u16 opcode, int index,
276 void (*cb)(struct pending_cmd *cmd, void *data),
277 void *data)
278{
279 struct list_head *p, *n;
280
Brian Gixa68668b2011-08-11 15:49:36 -0700281 BT_DBG(" %d", opcode);
282
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200283 list_for_each_safe(p, n, &cmd_list) {
284 struct pending_cmd *cmd;
285
286 cmd = list_entry(p, struct pending_cmd, list);
287
288 if (cmd->opcode != opcode)
289 continue;
290
291 if (index >= 0 && cmd->index != index)
292 continue;
293
294 cb(cmd, data);
295 }
296}
297
298static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
299{
300 struct list_head *p;
301
Brian Gixa68668b2011-08-11 15:49:36 -0700302 BT_DBG(" %d", opcode);
303
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 list_for_each(p, &cmd_list) {
305 struct pending_cmd *cmd;
306
307 cmd = list_entry(p, struct pending_cmd, list);
308
309 if (cmd->opcode != opcode)
310 continue;
311
312 if (index >= 0 && cmd->index != index)
313 continue;
314
315 return cmd;
316 }
317
318 return NULL;
319}
320
Johan Hedberga664b5b2011-02-19 12:06:02 -0300321static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200322{
Brian Gixa68668b2011-08-11 15:49:36 -0700323 BT_DBG(" %d", cmd->opcode);
324
Johan Hedberg73f22f62010-12-29 16:00:25 +0200325 list_del(&cmd->list);
326 mgmt_pending_free(cmd);
327}
328
Szymon Janc4e51eae2011-02-25 19:05:48 +0100329static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200331 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335
336 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Szymon Janc4e51eae2011-02-25 19:05:48 +0100338 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100340 if (len != sizeof(*cp))
341 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
342
Szymon Janc4e51eae2011-02-25 19:05:48 +0100343 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100345 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348
349 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200350 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352 goto failed;
353 }
354
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
356 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200357 goto failed;
358 }
359
Szymon Janc4e51eae2011-02-25 19:05:48 +0100360 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300361 if (!cmd) {
362 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300364 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200365
Johan Hedberg72a734e2010-12-30 00:38:22 +0200366 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200367 queue_work(hdev->workqueue, &hdev->power_on);
368 else
369 queue_work(hdev->workqueue, &hdev->power_off);
370
Johan Hedberg366a0332011-02-19 12:05:55 -0300371 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200372
373failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300376 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377}
378
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
380 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200382 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200383 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300384 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 u8 scan;
386 int err;
387
388 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200389
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100392 if (len != sizeof(*cp))
393 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
394
Szymon Janc4e51eae2011-02-25 19:05:48 +0100395 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100397 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400
401 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100402 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403 goto failed;
404 }
405
Szymon Janc4e51eae2011-02-25 19:05:48 +0100406 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
407 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
408 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200409 goto failed;
410 }
411
Johan Hedberg72a734e2010-12-30 00:38:22 +0200412 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200413 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100414 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200415 goto failed;
416 }
417
Szymon Janc4e51eae2011-02-25 19:05:48 +0100418 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300419 if (!cmd) {
420 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200421 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300422 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200423
424 scan = SCAN_PAGE;
425
Johan Hedberg72a734e2010-12-30 00:38:22 +0200426 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200427 scan |= SCAN_INQUIRY;
428
429 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
430 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300431 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200432
433failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200435 hci_dev_put(hdev);
436
437 return err;
438}
439
Szymon Janc4e51eae2011-02-25 19:05:48 +0100440static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
441 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200443 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300445 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 u8 scan;
447 int err;
448
449 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450
Szymon Janc4e51eae2011-02-25 19:05:48 +0100451 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100453 if (len != sizeof(*cp))
454 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
455
Szymon Janc4e51eae2011-02-25 19:05:48 +0100456 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100458 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
462 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100463 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464 goto failed;
465 }
466
Szymon Janc4e51eae2011-02-25 19:05:48 +0100467 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
468 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
469 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200470 goto failed;
471 }
472
Johan Hedberg72a734e2010-12-30 00:38:22 +0200473 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100474 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200475 goto failed;
476 }
477
Szymon Janc4e51eae2011-02-25 19:05:48 +0100478 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300479 if (!cmd) {
480 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200481 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300482 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200483
Johan Hedberg72a734e2010-12-30 00:38:22 +0200484 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200485 scan = SCAN_PAGE;
486 else
487 scan = 0;
488
489 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
490 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300491 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200492
493failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200495 hci_dev_put(hdev);
496
497 return err;
498}
499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
501 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200502{
503 struct sk_buff *skb;
504 struct mgmt_hdr *hdr;
505
Brian Gixa68668b2011-08-11 15:49:36 -0700506 BT_DBG("hci%d %d", index, event);
507
Johan Hedbergc542a062011-01-26 13:11:03 +0200508 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
509 if (!skb)
510 return -ENOMEM;
511
512 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
513
514 hdr = (void *) skb_put(skb, sizeof(*hdr));
515 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517 hdr->len = cpu_to_le16(data_len);
518
Szymon Janc4e51eae2011-02-25 19:05:48 +0100519 if (data)
520 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
522 hci_send_to_sock(NULL, skb, skip_sk);
523 kfree_skb(skb);
524
525 return 0;
526}
527
Johan Hedberg053f0212011-01-26 13:07:10 +0200528static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
529{
Johan Hedberga38528f2011-01-22 06:46:43 +0200530 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200531
Johan Hedberga38528f2011-01-22 06:46:43 +0200532 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200533
Szymon Janc4e51eae2011-02-25 19:05:48 +0100534 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200535}
536
Szymon Janc4e51eae2011-02-25 19:05:48 +0100537static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
538 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200539{
540 struct mgmt_mode *cp, ev;
541 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 int err;
543
544 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200545
Szymon Janc4e51eae2011-02-25 19:05:48 +0100546 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200547
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100548 if (len != sizeof(*cp))
549 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
550
Szymon Janc4e51eae2011-02-25 19:05:48 +0100551 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200552 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100553 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200556
557 if (cp->val)
558 set_bit(HCI_PAIRABLE, &hdev->flags);
559 else
560 clear_bit(HCI_PAIRABLE, &hdev->flags);
561
Szymon Janc4e51eae2011-02-25 19:05:48 +0100562 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200563 if (err < 0)
564 goto failed;
565
Johan Hedbergc542a062011-01-26 13:11:03 +0200566 ev.val = cp->val;
567
Szymon Janc4e51eae2011-02-25 19:05:48 +0100568 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200569
570failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200572 hci_dev_put(hdev);
573
574 return err;
575}
576
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300577#define EIR_FLAGS 0x01 /* flags */
578#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
579#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
580#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
581#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
582#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
583#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
584#define EIR_NAME_SHORT 0x08 /* shortened local name */
585#define EIR_NAME_COMPLETE 0x09 /* complete local name */
586#define EIR_TX_POWER 0x0A /* transmit power level */
587#define EIR_DEVICE_ID 0x10 /* device ID */
588
589#define PNP_INFO_SVCLASS_ID 0x1200
590
591static u8 bluetooth_base_uuid[] = {
592 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
593 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594};
595
596static u16 get_uuid16(u8 *uuid128)
597{
598 u32 val;
599 int i;
600
601 for (i = 0; i < 12; i++) {
602 if (bluetooth_base_uuid[i] != uuid128[i])
603 return 0;
604 }
605
606 memcpy(&val, &uuid128[12], 4);
607
608 val = le32_to_cpu(val);
609 if (val > 0xffff)
610 return 0;
611
612 return (u16) val;
613}
614
615static void create_eir(struct hci_dev *hdev, u8 *data)
616{
617 u8 *ptr = data;
618 u16 eir_len = 0;
619 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
620 int i, truncated = 0;
621 struct list_head *p;
622 size_t name_len;
623
624 name_len = strlen(hdev->dev_name);
625
626 if (name_len > 0) {
627 /* EIR Data type */
628 if (name_len > 48) {
629 name_len = 48;
630 ptr[1] = EIR_NAME_SHORT;
631 } else
632 ptr[1] = EIR_NAME_COMPLETE;
633
634 /* EIR Data length */
635 ptr[0] = name_len + 1;
636
637 memcpy(ptr + 2, hdev->dev_name, name_len);
638
639 eir_len += (name_len + 2);
640 ptr += (name_len + 2);
641 }
642
643 memset(uuid16_list, 0, sizeof(uuid16_list));
644
645 /* Group all UUID16 types */
646 list_for_each(p, &hdev->uuids) {
647 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
648 u16 uuid16;
649
650 uuid16 = get_uuid16(uuid->uuid);
651 if (uuid16 == 0)
652 return;
653
654 if (uuid16 < 0x1100)
655 continue;
656
657 if (uuid16 == PNP_INFO_SVCLASS_ID)
658 continue;
659
660 /* Stop if not enough space to put next UUID */
661 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
662 truncated = 1;
663 break;
664 }
665
666 /* Check for duplicates */
667 for (i = 0; uuid16_list[i] != 0; i++)
668 if (uuid16_list[i] == uuid16)
669 break;
670
671 if (uuid16_list[i] == 0) {
672 uuid16_list[i] = uuid16;
673 eir_len += sizeof(u16);
674 }
675 }
676
677 if (uuid16_list[0] != 0) {
678 u8 *length = ptr;
679
680 /* EIR Data type */
681 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
682
683 ptr += 2;
684 eir_len += 2;
685
686 for (i = 0; uuid16_list[i] != 0; i++) {
687 *ptr++ = (uuid16_list[i] & 0x00ff);
688 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
689 }
690
691 /* EIR Data length */
692 *length = (i * sizeof(u16)) + 1;
693 }
694}
695
696static int update_eir(struct hci_dev *hdev)
697{
698 struct hci_cp_write_eir cp;
699
700 if (!(hdev->features[6] & LMP_EXT_INQ))
701 return 0;
702
703 if (hdev->ssp_mode == 0)
704 return 0;
705
706 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
707 return 0;
708
709 memset(&cp, 0, sizeof(cp));
710
711 create_eir(hdev, cp.data);
712
713 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
714 return 0;
715
716 memcpy(hdev->eir, cp.data, sizeof(cp.data));
717
718 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
719}
720
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200721static u8 get_service_classes(struct hci_dev *hdev)
722{
723 struct list_head *p;
724 u8 val = 0;
725
726 list_for_each(p, &hdev->uuids) {
727 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
728
729 val |= uuid->svc_hint;
730 }
731
732 return val;
733}
734
735static int update_class(struct hci_dev *hdev)
736{
737 u8 cod[3];
738
739 BT_DBG("%s", hdev->name);
740
741 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
742 return 0;
743
744 cod[0] = hdev->minor_class;
745 cod[1] = hdev->major_class;
746 cod[2] = get_service_classes(hdev);
747
748 if (memcmp(cod, hdev->dev_class, 3) == 0)
749 return 0;
750
751 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
752}
753
Szymon Janc4e51eae2011-02-25 19:05:48 +0100754static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200755{
756 struct mgmt_cp_add_uuid *cp;
757 struct hci_dev *hdev;
758 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200759 int err;
760
761 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200762
Szymon Janc4e51eae2011-02-25 19:05:48 +0100763 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200764
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100765 if (len != sizeof(*cp))
766 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100770 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200773
774 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
775 if (!uuid) {
776 err = -ENOMEM;
777 goto failed;
778 }
779
780 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782
783 list_add(&uuid->list, &hdev->uuids);
784
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200785 err = update_class(hdev);
786 if (err < 0)
787 goto failed;
788
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300789 err = update_eir(hdev);
790 if (err < 0)
791 goto failed;
792
Szymon Janc4e51eae2011-02-25 19:05:48 +0100793 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
795failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200797 hci_dev_put(hdev);
798
799 return err;
800}
801
Szymon Janc4e51eae2011-02-25 19:05:48 +0100802static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200803{
804 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100805 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200806 struct hci_dev *hdev;
807 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 +0200808 int err, found;
809
810 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200811
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200813
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100814 if (len != sizeof(*cp))
815 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
816
Szymon Janc4e51eae2011-02-25 19:05:48 +0100817 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200818 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200822
823 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
824 err = hci_uuids_clear(hdev);
825 goto unlock;
826 }
827
828 found = 0;
829
830 list_for_each_safe(p, n, &hdev->uuids) {
831 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
832
833 if (memcmp(match->uuid, cp->uuid, 16) != 0)
834 continue;
835
836 list_del(&match->list);
837 found++;
838 }
839
840 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200842 goto unlock;
843 }
844
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845 err = update_class(hdev);
846 if (err < 0)
847 goto unlock;
848
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300849 err = update_eir(hdev);
850 if (err < 0)
851 goto unlock;
852
Szymon Janc4e51eae2011-02-25 19:05:48 +0100853 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200854
855unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200857 hci_dev_put(hdev);
858
859 return err;
860}
861
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
863 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864{
865 struct hci_dev *hdev;
866 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867 int err;
868
869 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873 if (len != sizeof(*cp))
874 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200877 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
882 hdev->major_class = cp->major;
883 hdev->minor_class = cp->minor;
884
885 err = update_class(hdev);
886
887 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200891 hci_dev_put(hdev);
892
893 return err;
894}
895
Szymon Janc4e51eae2011-02-25 19:05:48 +0100896static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
897 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898{
899 struct hci_dev *hdev;
900 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200901 int err;
902
903 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100905 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +0100906 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100907
Szymon Janc4e51eae2011-02-25 19:05:48 +0100908 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200909 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200915
916 if (cp->enable) {
917 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
918 err = 0;
919 } else {
920 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
921 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300922 if (err == 0)
923 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200924 }
925
926 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
928 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200931 hci_dev_put(hdev);
932
933 return err;
934}
935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200937{
938 struct hci_dev *hdev;
939 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100940 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300941 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200942
943 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100944
945 if (len < sizeof(*cp))
946 return -EINVAL;
947
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200948 key_count = get_unaligned_le16(&cp->key_count);
949
950 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300951 if (expected_len > len) {
952 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
953 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200954 return -EINVAL;
955 }
956
Szymon Janc4e51eae2011-02-25 19:05:48 +0100957 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200958 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200960
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200962 key_count);
963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200965
966 hci_link_keys_clear(hdev);
967
968 set_bit(HCI_LINK_KEYS, &hdev->flags);
969
970 if (cp->debug_keys)
971 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
972 else
973 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
974
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300975 len -= sizeof(*cp);
976 i = 0;
977
978 while (i < len) {
979 struct mgmt_key_info *key = (void *) cp->keys + i;
980
Brian Gixa68668b2011-08-11 15:49:36 -0700981 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300984 struct key_master_id *id = (void *) key->data;
985
986 if (key->dlen != sizeof(struct key_master_id))
987 continue;
988
Vinicius Costa Gomes1fa2de32011-07-08 18:31:45 -0300989 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
Brian Gixa68668b2011-08-11 15:49:36 -0700990 key->auth, id->ediv, id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300991
992 continue;
993 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200996 key->pin_len);
997 }
998
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300999 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001002 hci_dev_put(hdev);
1003
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001004 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001005}
1006
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_remove_key *cp;
1011 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001012 int err;
1013
1014 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001015
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001016 if (len != sizeof(*cp))
1017 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1018
Szymon Janc4e51eae2011-02-25 19:05:48 +01001019 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001020 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001024
1025 err = hci_remove_link_key(hdev, &cp->bdaddr);
1026 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001028 goto unlock;
1029 }
1030
1031 err = 0;
1032
1033 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1034 goto unlock;
1035
1036 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1037 if (conn) {
1038 struct hci_cp_disconnect dc;
1039
1040 put_unaligned_le16(conn->handle, &dc.handle);
1041 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001043 }
1044
1045unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001047 hci_dev_put(hdev);
1048
1049 return err;
1050}
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001053{
1054 struct hci_dev *hdev;
1055 struct mgmt_cp_disconnect *cp;
1056 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001057 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059 int err;
1060
1061 BT_DBG("");
1062
1063 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001065 if (len != sizeof(*cp))
1066 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1067
Szymon Janc4e51eae2011-02-25 19:05:48 +01001068 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001073
1074 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001075 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001076 goto failed;
1077 }
1078
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1080 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001081 goto failed;
1082 }
1083
1084 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1085 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001086 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1087 if (!conn) {
1088 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1089 ENOTCONN);
1090 goto failed;
1091 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001092 }
1093
Szymon Janc4e51eae2011-02-25 19:05:48 +01001094 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001095 if (!cmd) {
1096 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001097 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001098 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001099
1100 put_unaligned_le16(conn->handle, &dc.handle);
1101 dc.reason = 0x13; /* Remote User Terminated Connection */
1102
1103 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1104 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001105 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001106
1107failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001109 hci_dev_put(hdev);
1110
1111 return err;
1112}
1113
Szymon Janc8ce62842011-03-01 16:55:32 +01001114static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001115{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001116 struct mgmt_rp_get_connections *rp;
1117 struct hci_dev *hdev;
1118 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001119 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001120 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001121 int i, err;
1122
1123 BT_DBG("");
1124
Szymon Janc4e51eae2011-02-25 19:05:48 +01001125 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001126 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001127 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001130
1131 count = 0;
1132 list_for_each(p, &hdev->conn_hash.list) {
1133 count++;
1134 }
1135
Johan Hedberga38528f2011-01-22 06:46:43 +02001136 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1137 rp = kmalloc(rp_len, GFP_ATOMIC);
1138 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001139 err = -ENOMEM;
1140 goto unlock;
1141 }
1142
Johan Hedberg2784eb42011-01-21 13:56:35 +02001143 put_unaligned_le16(count, &rp->conn_count);
1144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 read_lock(&hci_dev_list_lock);
1146
Johan Hedberg2784eb42011-01-21 13:56:35 +02001147 i = 0;
1148 list_for_each(p, &hdev->conn_hash.list) {
1149 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1150
1151 bacpy(&rp->conn[i++], &c->dst);
1152 }
1153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 read_unlock(&hci_dev_list_lock);
1155
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001157
1158unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001159 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001161 hci_dev_put(hdev);
1162 return err;
1163}
1164
Szymon Janc4e51eae2011-02-25 19:05:48 +01001165static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1166 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001167{
1168 struct hci_dev *hdev;
1169 struct mgmt_cp_pin_code_reply *cp;
1170 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001171 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001172 int err;
1173
1174 BT_DBG("");
1175
1176 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001178 if (len != sizeof(*cp))
1179 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1180
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186
1187 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001188 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189 goto failed;
1190 }
1191
Szymon Janc4e51eae2011-02-25 19:05:48 +01001192 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001193 if (!cmd) {
1194 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001196 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001197
1198 bacpy(&reply.bdaddr, &cp->bdaddr);
1199 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001201
1202 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1203 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001204 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205
1206failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001208 hci_dev_put(hdev);
1209
1210 return err;
1211}
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1214 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215{
1216 struct hci_dev *hdev;
1217 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219 int err;
1220
1221 BT_DBG("");
1222
1223 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001225 if (len != sizeof(*cp))
1226 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1227 EINVAL);
1228
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001231 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1232 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001235
1236 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1238 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001239 goto failed;
1240 }
1241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1243 data, len);
1244 if (!cmd) {
1245 err = -ENOMEM;
1246 goto failed;
1247 }
1248
1249 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1250 &cp->bdaddr);
1251 if (err < 0)
1252 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001253
1254failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001256 hci_dev_put(hdev);
1257
1258 return err;
1259}
1260
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1262 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001263{
1264 struct hci_dev *hdev;
1265 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001266
1267 BT_DBG("");
1268
1269 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001270
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001271 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001272 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001273
Szymon Janc4e51eae2011-02-25 19:05:48 +01001274 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001275 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001276 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001279
1280 hdev->io_capability = cp->io_capability;
1281
1282 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001283 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001286 hci_dev_put(hdev);
1287
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001289}
1290
Johan Hedberge9a416b2011-02-19 12:05:56 -03001291static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1292{
1293 struct hci_dev *hdev = conn->hdev;
1294 struct list_head *p;
1295
1296 list_for_each(p, &cmd_list) {
1297 struct pending_cmd *cmd;
1298
1299 cmd = list_entry(p, struct pending_cmd, list);
1300
1301 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1302 continue;
1303
1304 if (cmd->index != hdev->id)
1305 continue;
1306
1307 if (cmd->user_data != conn)
1308 continue;
1309
1310 return cmd;
1311 }
1312
1313 return NULL;
1314}
1315
1316static void pairing_complete(struct pending_cmd *cmd, u8 status)
1317{
1318 struct mgmt_rp_pair_device rp;
1319 struct hci_conn *conn = cmd->user_data;
1320
Brian Gixa68668b2011-08-11 15:49:36 -07001321 BT_DBG(" %u", status);
1322
Johan Hedberge9a416b2011-02-19 12:05:56 -03001323 bacpy(&rp.bdaddr, &conn->dst);
1324 rp.status = status;
1325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001327
1328 /* So we don't get further callbacks for this connection */
1329 conn->connect_cfm_cb = NULL;
1330 conn->security_cfm_cb = NULL;
1331 conn->disconn_cfm_cb = NULL;
1332
1333 hci_conn_put(conn);
1334
Johan Hedberga664b5b2011-02-19 12:06:02 -03001335 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336}
1337
1338static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1339{
1340 struct pending_cmd *cmd;
1341
Brian Gixa68668b2011-08-11 15:49:36 -07001342 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
1344 cmd = find_pairing(conn);
1345 if (!cmd) {
1346 BT_DBG("Unable to find a pending command");
1347 return;
1348 }
1349
1350 pairing_complete(cmd, status);
1351}
1352
Brian Gixa68668b2011-08-11 15:49:36 -07001353static void security_complete_cb(struct hci_conn *conn, u8 status)
1354{
1355 struct pending_cmd *cmd;
1356
1357 BT_DBG(" %u", status);
1358
1359 cmd = find_pairing(conn);
1360 if (!cmd) {
1361 BT_DBG("Unable to find a pending command");
1362 return;
1363 }
1364
1365 if (conn->type == LE_LINK)
1366 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1367 status ? 0 : 1);
1368 else
1369 pairing_complete(cmd, status);
1370}
1371
1372static void connect_complete_cb(struct hci_conn *conn, u8 status)
1373{
1374 struct pending_cmd *cmd;
1375
1376 BT_DBG("conn: %p %u", conn, status);
1377
1378 cmd = find_pairing(conn);
1379 if (!cmd) {
1380 BT_DBG("Unable to find a pending command");
1381 return;
1382 }
1383
1384 hci_conn_put(conn);
1385}
1386
1387static void discovery_terminated(struct pending_cmd *cmd, void *data)
1388{
1389 struct mgmt_mode ev = {0};
1390 struct disco_interleave *ilp = cmd->param;
1391
1392 BT_DBG("");
1393 del_timer_sync(&ilp->le_timer);
1394 del_timer_sync(&ilp->timer);
1395 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1396
1397 list_del(&cmd->list);
1398
1399 mgmt_pending_free(cmd);
1400}
1401
Szymon Janc4e51eae2011-02-25 19:05:48 +01001402static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001403{
1404 struct hci_dev *hdev;
1405 struct mgmt_cp_pair_device *cp;
1406 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001407 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001408 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001409 int err;
1410
1411 BT_DBG("");
1412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001414
Johan Hedberge9a416b2011-02-19 12:05:56 -03001415 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001416 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001419
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301420 cp = (void *) data;
1421
1422 if (len != sizeof(*cp))
1423 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1424
1425 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1426 io_cap = cp->io_cap;
1427 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001428 sec_level = BT_SECURITY_MEDIUM;
1429 auth_type = HCI_AT_DEDICATED_BONDING;
1430 } else {
1431 sec_level = BT_SECURITY_HIGH;
1432 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1433 }
1434
Brian Gixa68668b2011-08-11 15:49:36 -07001435 if (hci_find_adv_entry(hdev, &cp->bdaddr)) {
1436 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1437 auth_type);
1438 if (conn && !IS_ERR(conn))
1439 hci_conn_hold(conn);
1440 } else {
1441 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1442 if (io_cap == 0x04)
1443 io_cap = 0x01;
1444 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1445 auth_type);
1446 }
1447
Ville Tervo30e76272011-02-22 16:10:53 -03001448 if (IS_ERR(conn)) {
1449 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001450 goto unlock;
1451 }
1452
1453 if (conn->connect_cfm_cb) {
1454 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001456 goto unlock;
1457 }
1458
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001460 if (!cmd) {
1461 err = -ENOMEM;
1462 hci_conn_put(conn);
1463 goto unlock;
1464 }
1465
Brian Gixa68668b2011-08-11 15:49:36 -07001466 conn->connect_cfm_cb = connect_complete_cb;
1467 conn->security_cfm_cb = security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001468 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001469 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001470 cmd->user_data = conn;
1471
1472 if (conn->state == BT_CONNECTED &&
1473 hci_conn_security(conn, sec_level, auth_type))
1474 pairing_complete(cmd, 0);
1475
1476 err = 0;
1477
1478unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001480 hci_dev_put(hdev);
1481
1482 return err;
1483}
1484
Szymon Janc4e51eae2011-02-25 19:05:48 +01001485static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001486 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001487{
1488 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001489 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001490 struct pending_cmd *cmd;
1491 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001492 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001493 int err;
1494
Brian Gixa68668b2011-08-11 15:49:36 -07001495 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001496
Brian Gixa68668b2011-08-11 15:49:36 -07001497 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001498 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001499 else
1500 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001501
Brian Gixa68668b2011-08-11 15:49:36 -07001502 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001503 return cmd_status(sk, index, mgmt_op, EINVAL);
1504
Szymon Janc4e51eae2011-02-25 19:05:48 +01001505 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001506 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001510
Johan Hedberga5c29682011-02-19 12:05:57 -03001511 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001512 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001513 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001514 }
1515
Brian Gixa68668b2011-08-11 15:49:36 -07001516 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1517 if (le_conn) {
1518 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1519 goto done;
1520 }
1521 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1522 "Reject" : "Accept");
1523
Szymon Janc4e51eae2011-02-25 19:05:48 +01001524 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001525 if (!cmd) {
1526 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001527 goto done;
1528 }
1529
1530 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1531 if (err < 0)
1532 mgmt_pending_remove(cmd);
1533
1534done:
1535 hci_dev_unlock(hdev);
1536 hci_dev_put(hdev);
1537
1538 return err;
1539}
1540
1541static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1542 u16 len)
1543{
1544 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1545 struct hci_cp_remote_name_req hci_cp;
1546 struct hci_dev *hdev;
1547 struct pending_cmd *cmd;
1548 int err;
1549
1550 BT_DBG("");
1551
1552 if (len != sizeof(*mgmt_cp))
1553 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1554
1555 hdev = hci_dev_get(index);
1556 if (!hdev)
1557 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1558
1559 hci_dev_lock(hdev);
1560
1561 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1562 if (!cmd) {
1563 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001564 goto failed;
1565 }
1566
Brian Gixa68668b2011-08-11 15:49:36 -07001567 memset(&hci_cp, 0, sizeof(hci_cp));
1568 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1569 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1570 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001571 if (err < 0)
1572 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001573
1574failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001576 hci_dev_put(hdev);
1577
1578 return err;
1579}
1580
Johan Hedbergb312b1612011-03-16 14:29:37 +02001581static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1582 u16 len)
1583{
1584 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1585 struct hci_cp_write_local_name hci_cp;
1586 struct hci_dev *hdev;
1587 struct pending_cmd *cmd;
1588 int err;
1589
1590 BT_DBG("");
1591
1592 if (len != sizeof(*mgmt_cp))
1593 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1594
1595 hdev = hci_dev_get(index);
1596 if (!hdev)
1597 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001600
1601 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1602 if (!cmd) {
1603 err = -ENOMEM;
1604 goto failed;
1605 }
1606
1607 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1608 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1609 &hci_cp);
1610 if (err < 0)
1611 mgmt_pending_remove(cmd);
1612
1613failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001615 hci_dev_put(hdev);
1616
1617 return err;
1618}
1619
Brian Gixa68668b2011-08-11 15:49:36 -07001620static void discovery_rsp(struct pending_cmd *cmd, void *data)
1621{
1622 struct mgmt_mode ev;
1623
1624 BT_DBG("");
1625 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1626 ev.val = 1;
1627 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1628 } else {
1629 ev.val = 0;
1630 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1631 NULL, 0);
1632 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1633 struct disco_interleave *ilp = cmd->param;
1634
1635 del_timer_sync(&ilp->le_timer);
1636 del_timer_sync(&ilp->timer);
1637 }
1638 }
1639
1640 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1641
1642 list_del(&cmd->list);
1643
1644 mgmt_pending_free(cmd);
1645}
1646
1647void mgmt_inquiry_started(u16 index)
1648{
1649 BT_DBG("");
1650 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1651 discovery_rsp, NULL);
1652}
1653
1654void mgmt_inquiry_complete_evt(u16 index, u8 status)
1655{
1656 struct hci_dev *hdev;
1657 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1658 struct pending_cmd *cmd;
1659 int err = -1;
1660
1661 BT_DBG("");
1662
1663 hdev = hci_dev_get(index);
1664 if (!hdev || !lmp_le_capable(hdev)) {
1665 struct mgmt_mode cp = {0};
1666
1667 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1668 discovery_terminated, NULL);
1669
1670 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
1671 return;
1672 }
1673
1674 hci_dev_lock(hdev);
1675
1676 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1677 if (cmd && cmd->param) {
1678 struct disco_interleave *ilp = cmd->param;
1679
1680 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1681 sizeof(le_cp), &le_cp);
1682 if (err >= 0) {
1683 mod_timer(&ilp->le_timer, jiffies +
1684 msecs_to_jiffies(ilp->int_phase * 1000));
1685 ilp->mode = SCAN_LE;
1686 } else
1687 ilp->mode = SCAN_IDLE;
1688 }
1689
1690 if (err < 0)
1691 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1692 discovery_terminated, NULL);
1693
1694 hci_dev_unlock(hdev);
1695 hci_dev_put(hdev);
1696}
1697
1698static void disco_to(unsigned long data)
1699{
1700 struct disco_interleave *ilp = (void *)data;
1701 struct hci_dev *hdev;
1702 struct pending_cmd *cmd;
1703
1704 BT_DBG("hci%d", ilp->index);
1705
1706 del_timer_sync(&ilp->le_timer);
1707 hdev = hci_dev_get(ilp->index);
1708
1709 if (hdev) {
1710 hci_dev_lock(hdev);
1711
1712 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1713
1714 if (ilp->mode != SCAN_IDLE) {
1715 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1716
1717 if (ilp->mode == SCAN_LE)
1718 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1719 sizeof(le_cp), &le_cp);
1720 else
1721 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1722 0, NULL);
1723
1724 ilp->mode = SCAN_IDLE;
1725 }
1726
1727 if (cmd) {
1728 struct mgmt_mode cp = {0};
1729
1730 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1731 sizeof(cp), NULL);
1732 mgmt_pending_remove(cmd);
1733 }
1734
1735 hci_dev_unlock(hdev);
1736 }
1737}
1738
1739static void disco_le_to(unsigned long data)
1740{
1741 struct disco_interleave *ilp = (void *)data;
1742 struct hci_dev *hdev;
1743 struct pending_cmd *cmd;
1744 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1745
1746 BT_DBG("hci%d", ilp->index);
1747
1748 hdev = hci_dev_get(ilp->index);
1749 del_timer_sync(&ilp->le_timer);
1750
1751 if (hdev) {
1752 hci_dev_lock(hdev);
1753
1754 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1755
1756 if (ilp->mode == SCAN_LE)
1757 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1758 sizeof(le_cp), &le_cp);
1759
1760 /* re-start BR scan */
1761 if (cmd) {
1762 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1763 ilp->int_phase *= 2;
1764 ilp->int_count = 0;
1765 cp.num_rsp = (u8) ilp->int_phase;
1766 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1767 ilp->mode = SCAN_BR;
1768 } else
1769 ilp->mode = SCAN_IDLE;
1770
1771 hci_dev_unlock(hdev);
1772 }
1773}
1774
1775static int start_discovery(struct sock *sk, u16 index)
1776{
1777 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1778 struct hci_dev *hdev;
1779 struct pending_cmd *cmd;
1780 int err;
1781
1782 BT_DBG("");
1783
1784 hdev = hci_dev_get(index);
1785 if (!hdev)
1786 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1787
1788 hci_dev_lock(hdev);
1789
1790 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1791 if (!cmd) {
1792 err = -ENOMEM;
1793 goto failed;
1794 }
1795
1796 /* If LE Capable, we will alternate between BR/EDR and LE */
1797 if (lmp_le_capable(hdev)) {
1798 struct hci_cp_le_set_scan_parameters le_cp;
1799
1800 /* Shorten BR scan params */
1801 cp.num_rsp = 1;
1802 cp.length /= 2;
1803
1804 /* Setup LE scan params */
1805 memset(&le_cp, 0, sizeof(le_cp));
1806 le_cp.type = 0x01; /* Active scanning */
1807 /* The recommended value for scan interval and window is
1808 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1809 le_cp.interval = cpu_to_le16(0x0012);
1810 le_cp.window = cpu_to_le16(0x0012);
1811 le_cp.own_bdaddr_type = 0; /* Public address */
1812 le_cp.filter = 0; /* Accept all adv packets */
1813
1814 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1815 sizeof(le_cp), &le_cp);
1816 }
1817
1818 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1819
1820 if (err < 0)
1821 mgmt_pending_remove(cmd);
1822 else if (lmp_le_capable(hdev)) {
1823 struct disco_interleave il, *ilp;
1824
1825 il.int_phase = 1;
1826 il.int_count = 0;
1827 il.index = index;
1828 il.mode = SCAN_BR;
1829 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1830 sizeof(struct disco_interleave));
1831 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1832 if (cmd) {
1833 ilp = cmd->param;
1834 setup_timer(&ilp->le_timer, disco_le_to,
1835 (unsigned long) ilp);
1836 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1837 mod_timer(&ilp->timer,
1838 jiffies + msecs_to_jiffies(20000));
1839 }
1840 }
1841
1842failed:
1843 hci_dev_unlock(hdev);
1844 hci_dev_put(hdev);
1845
1846 return err;
1847}
1848
1849static int stop_discovery(struct sock *sk, u16 index)
1850{
1851 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1852 struct mgmt_mode mode_cp = {0};
1853 struct disco_interleave *ilp = NULL;
1854 struct hci_dev *hdev;
1855 struct pending_cmd *cmd = NULL;
1856 int err = -EPERM;
1857
1858 BT_DBG("");
1859
1860 hdev = hci_dev_get(index);
1861 if (!hdev)
1862 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1863
1864 hci_dev_lock(hdev);
1865
1866 if (lmp_le_capable(hdev)) {
1867 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1868 if (!cmd) {
1869 err = -ENOMEM;
1870 goto failed;
1871 }
1872
1873 ilp = cmd->param;
1874 }
1875
1876 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1877 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1878 sizeof(le_cp), &le_cp);
1879
1880 if (err < 0) {
1881 if (!ilp || (ilp->mode == SCAN_BR))
1882 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1883 0, NULL);
1884 }
1885
1886 if (ilp) {
1887 ilp->mode = SCAN_IDLE;
1888 del_timer_sync(&ilp->le_timer);
1889 del_timer_sync(&ilp->timer);
1890 }
1891
1892 if (err < 0 && cmd)
1893 mgmt_pending_remove(cmd);
1894
1895 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1896
1897failed:
1898 hci_dev_unlock(hdev);
1899 hci_dev_put(hdev);
1900
1901 if (err < 0)
1902 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1903 else
1904 return err;
1905}
1906
Szymon Jancc35938b2011-03-22 13:12:21 +01001907static int read_local_oob_data(struct sock *sk, u16 index)
1908{
1909 struct hci_dev *hdev;
1910 struct pending_cmd *cmd;
1911 int err;
1912
1913 BT_DBG("hci%u", index);
1914
1915 hdev = hci_dev_get(index);
1916 if (!hdev)
1917 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1918 ENODEV);
1919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001921
1922 if (!test_bit(HCI_UP, &hdev->flags)) {
1923 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1924 ENETDOWN);
1925 goto unlock;
1926 }
1927
1928 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1929 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1930 EOPNOTSUPP);
1931 goto unlock;
1932 }
1933
1934 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1935 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1936 goto unlock;
1937 }
1938
1939 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1940 if (!cmd) {
1941 err = -ENOMEM;
1942 goto unlock;
1943 }
1944
1945 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1946 if (err < 0)
1947 mgmt_pending_remove(cmd);
1948
1949unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001951 hci_dev_put(hdev);
1952
1953 return err;
1954}
1955
Szymon Janc2763eda2011-03-22 13:12:22 +01001956static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1957 u16 len)
1958{
1959 struct hci_dev *hdev;
1960 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1961 int err;
1962
1963 BT_DBG("hci%u ", index);
1964
1965 if (len != sizeof(*cp))
1966 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1967 EINVAL);
1968
1969 hdev = hci_dev_get(index);
1970 if (!hdev)
1971 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1972 ENODEV);
1973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001974 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001975
1976 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1977 cp->randomizer);
1978 if (err < 0)
1979 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1980 else
1981 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1982 0);
1983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001985 hci_dev_put(hdev);
1986
1987 return err;
1988}
1989
1990static int remove_remote_oob_data(struct sock *sk, u16 index,
1991 unsigned char *data, u16 len)
1992{
1993 struct hci_dev *hdev;
1994 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1995 int err;
1996
1997 BT_DBG("hci%u ", index);
1998
1999 if (len != sizeof(*cp))
2000 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2001 EINVAL);
2002
2003 hdev = hci_dev_get(index);
2004 if (!hdev)
2005 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2006 ENODEV);
2007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002009
2010 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2011 if (err < 0)
2012 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2013 -err);
2014 else
2015 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2016 NULL, 0);
2017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002019 hci_dev_put(hdev);
2020
2021 return err;
2022}
2023
Johan Hedberg03811012010-12-08 00:21:06 +02002024int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2025{
2026 unsigned char *buf;
2027 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002028 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002029 int err;
2030
2031 BT_DBG("got %zu bytes", msglen);
2032
2033 if (msglen < sizeof(*hdr))
2034 return -EINVAL;
2035
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002036 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002037 if (!buf)
2038 return -ENOMEM;
2039
2040 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2041 err = -EFAULT;
2042 goto done;
2043 }
2044
2045 hdr = (struct mgmt_hdr *) buf;
2046 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002047 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002048 len = get_unaligned_le16(&hdr->len);
2049
2050 if (len != msglen - sizeof(*hdr)) {
2051 err = -EINVAL;
2052 goto done;
2053 }
2054
Brian Gixa68668b2011-08-11 15:49:36 -07002055 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002056 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002057 case MGMT_OP_READ_VERSION:
2058 err = read_version(sk);
2059 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002060 case MGMT_OP_READ_INDEX_LIST:
2061 err = read_index_list(sk);
2062 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002063 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002064 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002065 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002066 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002067 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002068 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002069 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002070 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002071 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002072 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002073 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002074 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002075 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002076 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002077 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002078 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002079 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002080 break;
2081 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002082 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002083 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002085 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002086 break;
2087 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002088 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002089 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002090 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002091 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002092 break;
2093 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002094 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002095 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002096 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002097 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002098 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002099 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002100 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002101 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002102 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002104 break;
2105 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002106 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002107 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002108 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002109 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002110 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002111 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002113 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002114 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002115 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002116 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002117 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2118 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002119 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002120 case MGMT_OP_SET_LOCAL_NAME:
2121 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2122 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002123 case MGMT_OP_START_DISCOVERY:
2124 err = start_discovery(sk, index);
2125 break;
2126 case MGMT_OP_STOP_DISCOVERY:
2127 err = stop_discovery(sk, index);
2128 break;
2129 case MGMT_OP_RESOLVE_NAME:
2130 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2131 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002132 case MGMT_OP_READ_LOCAL_OOB_DATA:
2133 err = read_local_oob_data(sk, index);
2134 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002135 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2136 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2137 break;
2138 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2139 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2140 len);
2141 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142
Johan Hedberg03811012010-12-08 00:21:06 +02002143 default:
2144 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002146 break;
2147 }
2148
Johan Hedberge41d8b42010-12-13 21:07:03 +02002149 if (err < 0)
2150 goto done;
2151
Johan Hedberg03811012010-12-08 00:21:06 +02002152 err = msglen;
2153
2154done:
2155 kfree(buf);
2156 return err;
2157}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002158
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002159int mgmt_index_added(u16 index)
2160{
Brian Gixa68668b2011-08-11 15:49:36 -07002161 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002162 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002163}
2164
2165int mgmt_index_removed(u16 index)
2166{
Brian Gixa68668b2011-08-11 15:49:36 -07002167 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002168 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002169}
2170
Johan Hedberg73f22f62010-12-29 16:00:25 +02002171struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002172 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002173 struct sock *sk;
2174};
2175
Johan Hedberg72a734e2010-12-30 00:38:22 +02002176static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002177{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002178 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002179 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002180
Johan Hedberg72a734e2010-12-30 00:38:22 +02002181 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002182 return;
2183
Johan Hedberg053f0212011-01-26 13:07:10 +02002184 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002185
2186 list_del(&cmd->list);
2187
2188 if (match->sk == NULL) {
2189 match->sk = cmd->sk;
2190 sock_hold(match->sk);
2191 }
2192
2193 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002194}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002195
2196int mgmt_powered(u16 index, u8 powered)
2197{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002198 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002199 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002200 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002201
Brian Gixa68668b2011-08-11 15:49:36 -07002202 BT_DBG("hci%u %d", index, powered);
2203
Johan Hedberg72a734e2010-12-30 00:38:22 +02002204 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002205
Johan Hedberg72a734e2010-12-30 00:38:22 +02002206 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002207
Szymon Janc4e51eae2011-02-25 19:05:48 +01002208 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002209
2210 if (match.sk)
2211 sock_put(match.sk);
2212
2213 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002214}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002215
Johan Hedberg73f22f62010-12-29 16:00:25 +02002216int mgmt_discoverable(u16 index, u8 discoverable)
2217{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002218 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002219 struct cmd_lookup match = { discoverable, NULL };
2220 int ret;
2221
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002222 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002223
Johan Hedberg72a734e2010-12-30 00:38:22 +02002224 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002225
Szymon Janc4e51eae2011-02-25 19:05:48 +01002226 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2227 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002228
2229 if (match.sk)
2230 sock_put(match.sk);
2231
2232 return ret;
2233}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002234
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002235int mgmt_connectable(u16 index, u8 connectable)
2236{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002237 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002238 struct cmd_lookup match = { connectable, NULL };
2239 int ret;
2240
Johan Hedberg72a734e2010-12-30 00:38:22 +02002241 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002242
Johan Hedberg72a734e2010-12-30 00:38:22 +02002243 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002244
Szymon Janc4e51eae2011-02-25 19:05:48 +01002245 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002246
2247 if (match.sk)
2248 sock_put(match.sk);
2249
2250 return ret;
2251}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002252
Brian Gixa68668b2011-08-11 15:49:36 -07002253int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002254{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002255 struct mgmt_ev_new_key *ev;
2256 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002257
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002258 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2259 ev = kzalloc(total, GFP_ATOMIC);
2260 if (!ev)
2261 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002262
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002263 bacpy(&ev->key.bdaddr, &key->bdaddr);
2264 ev->key.type = key->type;
2265 memcpy(ev->key.val, key->val, 16);
2266 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002267 ev->key.auth = key->auth;
2268 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002269 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002270
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002271 memcpy(ev->key.data, key->data, key->dlen);
2272
2273 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2274
2275 kfree(ev);
2276
2277 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002278}
Johan Hedbergf7520542011-01-20 12:34:39 +02002279
2280int mgmt_connected(u16 index, bdaddr_t *bdaddr)
2281{
2282 struct mgmt_ev_connected ev;
2283
Johan Hedbergf7520542011-01-20 12:34:39 +02002284 bacpy(&ev.bdaddr, bdaddr);
2285
Szymon Janc4e51eae2011-02-25 19:05:48 +01002286 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002287}
2288
Johan Hedberg8962ee72011-01-20 12:40:27 +02002289static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2290{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002291 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002292 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002293 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002294
Johan Hedberga38528f2011-01-22 06:46:43 +02002295 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002296
Szymon Janc4e51eae2011-02-25 19:05:48 +01002297 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002298
2299 *sk = cmd->sk;
2300 sock_hold(*sk);
2301
Johan Hedberga664b5b2011-02-19 12:06:02 -03002302 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002303}
2304
Johan Hedbergf7520542011-01-20 12:34:39 +02002305int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2306{
2307 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002308 struct sock *sk = NULL;
2309 int err;
2310
2311 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002312
Johan Hedbergf7520542011-01-20 12:34:39 +02002313 bacpy(&ev.bdaddr, bdaddr);
2314
Szymon Janc4e51eae2011-02-25 19:05:48 +01002315 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002316
2317 if (sk)
2318 sock_put(sk);
2319
2320 return err;
2321}
2322
2323int mgmt_disconnect_failed(u16 index)
2324{
2325 struct pending_cmd *cmd;
2326 int err;
2327
2328 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2329 if (!cmd)
2330 return -ENOENT;
2331
Szymon Janc4e51eae2011-02-25 19:05:48 +01002332 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002333
Johan Hedberga664b5b2011-02-19 12:06:02 -03002334 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335
2336 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002337}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002338
2339int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2340{
2341 struct mgmt_ev_connect_failed ev;
2342
Johan Hedberg17d5c042011-01-22 06:09:08 +02002343 bacpy(&ev.bdaddr, bdaddr);
2344 ev.status = status;
2345
Szymon Janc4e51eae2011-02-25 19:05:48 +01002346 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002347}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002350{
2351 struct mgmt_ev_pin_code_request ev;
2352
Brian Gixa68668b2011-08-11 15:49:36 -07002353 BT_DBG("hci%u", index);
2354
Johan Hedberg980e1a52011-01-22 06:10:07 +02002355 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002356 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002357
Szymon Janc4e51eae2011-02-25 19:05:48 +01002358 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2359 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002360}
2361
2362int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2363{
2364 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002365 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002366 int err;
2367
2368 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2369 if (!cmd)
2370 return -ENOENT;
2371
Johan Hedbergac56fb12011-02-19 12:05:59 -03002372 bacpy(&rp.bdaddr, bdaddr);
2373 rp.status = status;
2374
Szymon Janc4e51eae2011-02-25 19:05:48 +01002375 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2376 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002377
Johan Hedberga664b5b2011-02-19 12:06:02 -03002378 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002379
2380 return err;
2381}
2382
2383int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2384{
2385 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002386 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387 int err;
2388
2389 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2390 if (!cmd)
2391 return -ENOENT;
2392
Johan Hedbergac56fb12011-02-19 12:05:59 -03002393 bacpy(&rp.bdaddr, bdaddr);
2394 rp.status = status;
2395
Szymon Janc4e51eae2011-02-25 19:05:48 +01002396 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2397 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002398
Johan Hedberga664b5b2011-02-19 12:06:02 -03002399 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002400
2401 return err;
2402}
Johan Hedberga5c29682011-02-19 12:05:57 -03002403
Brian Gixa68668b2011-08-11 15:49:36 -07002404int mgmt_user_confirm_request(u16 index, u8 event,
2405 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002406{
2407 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002408 struct hci_conn *conn = NULL;
2409 struct hci_dev *hdev;
2410 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2411
2412 BT_DBG("hci%u", index);
2413
2414 hdev = hci_dev_get(index);
2415
2416 if (hdev)
2417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2418
2419 ev.auto_confirm = 0;
2420
2421 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2422 goto no_auto_confirm;
2423
2424 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2425 rem_cap = conn->remote_cap;
2426 loc_mitm = conn->auth_type & 0x01;
2427 rem_mitm = conn->remote_auth & 0x01;
2428
2429 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2430 goto no_auto_confirm;
2431
2432
2433 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2434 ev.auto_confirm = 1;
2435
2436no_auto_confirm:
2437 bacpy(&ev.bdaddr, bdaddr);
2438 ev.event = event;
2439 put_unaligned_le32(value, &ev.value);
2440
2441 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2442 NULL);
2443}
2444
2445int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2446{
2447 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002448
2449 BT_DBG("hci%u", index);
2450
Johan Hedberga5c29682011-02-19 12:05:57 -03002451 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002452
Brian Gixa68668b2011-08-11 15:49:36 -07002453 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002454 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002455}
2456
2457static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2458 u8 opcode)
2459{
2460 struct pending_cmd *cmd;
2461 struct mgmt_rp_user_confirm_reply rp;
2462 int err;
2463
2464 cmd = mgmt_pending_find(opcode, index);
2465 if (!cmd)
2466 return -ENOENT;
2467
Johan Hedberga5c29682011-02-19 12:05:57 -03002468 bacpy(&rp.bdaddr, bdaddr);
2469 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002470 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002471
Johan Hedberga664b5b2011-02-19 12:06:02 -03002472 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002473
2474 return err;
2475}
2476
2477int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2478{
2479 return confirm_reply_complete(index, bdaddr, status,
2480 MGMT_OP_USER_CONFIRM_REPLY);
2481}
2482
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002483int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002484{
2485 return confirm_reply_complete(index, bdaddr, status,
2486 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2487}
Johan Hedberg2a611692011-02-19 12:06:00 -03002488
2489int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2490{
2491 struct mgmt_ev_auth_failed ev;
2492
Johan Hedberg2a611692011-02-19 12:06:00 -03002493 bacpy(&ev.bdaddr, bdaddr);
2494 ev.status = status;
2495
Szymon Janc4e51eae2011-02-25 19:05:48 +01002496 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002497}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002498
2499int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2500{
2501 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002502 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002503 struct mgmt_cp_set_local_name ev;
2504 int err;
2505
2506 memset(&ev, 0, sizeof(ev));
2507 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2508
2509 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2510 if (!cmd)
2511 goto send_event;
2512
2513 if (status) {
2514 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2515 goto failed;
2516 }
2517
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002518 hdev = hci_dev_get(index);
2519 if (hdev) {
2520 hci_dev_lock_bh(hdev);
2521 update_eir(hdev);
2522 hci_dev_unlock_bh(hdev);
2523 hci_dev_put(hdev);
2524 }
2525
Johan Hedbergb312b1612011-03-16 14:29:37 +02002526 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2527 sizeof(ev));
2528 if (err < 0)
2529 goto failed;
2530
2531send_event:
2532 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2533 cmd ? cmd->sk : NULL);
2534
2535failed:
2536 if (cmd)
2537 mgmt_pending_remove(cmd);
2538 return err;
2539}
Szymon Jancc35938b2011-03-22 13:12:21 +01002540
2541int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2542 u8 status)
2543{
2544 struct pending_cmd *cmd;
2545 int err;
2546
2547 BT_DBG("hci%u status %u", index, status);
2548
2549 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2550 if (!cmd)
2551 return -ENOENT;
2552
2553 if (status) {
2554 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2555 EIO);
2556 } else {
2557 struct mgmt_rp_read_local_oob_data rp;
2558
2559 memcpy(rp.hash, hash, sizeof(rp.hash));
2560 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2561
2562 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2563 &rp, sizeof(rp));
2564 }
2565
2566 mgmt_pending_remove(cmd);
2567
2568 return err;
2569}
Johan Hedberge17acd42011-03-30 23:57:16 +03002570
Brian Gixa68668b2011-08-11 15:49:36 -07002571int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2572 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002573{
2574 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002575 struct hci_dev *hdev = hci_dev_get(index);
2576 struct pending_cmd *cmd;
2577 int err;
2578
2579 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002580
2581 memset(&ev, 0, sizeof(ev));
2582
2583 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002584 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002585 ev.type = type;
2586 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002587
Brian Gixa68668b2011-08-11 15:49:36 -07002588 if (dev_class)
2589 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002590
Brian Gixa68668b2011-08-11 15:49:36 -07002591 if (eir && eir_len)
2592 memcpy(ev.eir, eir, eir_len);
2593
2594 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2595
2596 if (err < 0)
2597 return err;
2598
2599 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2600 if (cmd) {
2601 struct disco_interleave *ilp = cmd->param;
2602
2603 ilp->int_count++;
2604 if (hdev && ilp->int_count >= ilp->int_phase) {
2605 /* Inquiry scan for General Discovery LAP */
2606 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2607 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2608 ilp->int_phase *= 2;
2609 ilp->int_count = 0;
2610 if (ilp->mode == SCAN_LE) {
2611 /* cancel LE scan */
2612 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2613 sizeof(le_cp), &le_cp);
2614 /* start BR scan */
2615 cp.num_rsp = (u8) ilp->int_phase;
2616 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2617 sizeof(cp), &cp);
2618 ilp->mode = SCAN_BR;
2619 del_timer_sync(&ilp->le_timer);
2620 }
2621 }
2622 }
2623
2624 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002625}
Johan Hedberga88a9652011-03-30 13:18:12 +03002626
Brian Gixa68668b2011-08-11 15:49:36 -07002627
2628int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002629{
2630 struct mgmt_ev_remote_name ev;
2631
2632 memset(&ev, 0, sizeof(ev));
2633
2634 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002635 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002636 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2637
2638 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2639}