blob: 7a906d6e0236e7d2e1dec96fa06808baa8968a2d [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200573 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574
575 BT_DBG("%s", hdev->name);
576
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200577 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200578 return 0;
579
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200580 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 return 0;
582
583 cod[0] = hdev->minor_class;
584 cod[1] = hdev->major_class;
585 cod[2] = get_service_classes(hdev);
586
587 if (memcmp(cod, hdev->dev_class, 3) == 0)
588 return 0;
589
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200590 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
591 if (err == 0)
592 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
593
594 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595}
596
Johan Hedberg7d785252011-12-15 00:47:39 +0200597static void service_cache_off(struct work_struct *work)
598{
599 struct hci_dev *hdev = container_of(work, struct hci_dev,
600 service_cache.work);
601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200603 return;
604
605 hci_dev_lock(hdev);
606
607 update_eir(hdev);
608 update_class(hdev);
609
610 hci_dev_unlock(hdev);
611}
612
613static void mgmt_init_hdev(struct hci_dev *hdev)
614{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200615 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
617
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200618 /* Non-mgmt controlled devices get this bit set
619 * implicitly so that pairing works for them, however
620 * for mgmt we require user-space to explicitly enable
621 * it
622 */
623 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
624 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200625}
626
Johan Hedberg03811012010-12-08 00:21:06 +0200627static int read_controller_info(struct sock *sk, u16 index)
628{
629 struct mgmt_rp_read_info rp;
630 struct hci_dev *hdev;
631
632 BT_DBG("sock %p hci%u", sk, index);
633
634 hdev = hci_dev_get(index);
635 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200636 return cmd_status(sk, index, MGMT_OP_READ_INFO,
637 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300639 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200640
Johan Hedberg7d785252011-12-15 00:47:39 +0200641 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
642 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200643
644 memset(&rp, 0, sizeof(rp));
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.version = hdev->hci_ver;
649
Johan Hedberg03811012010-12-08 00:21:06 +0200650 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651
652 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
653 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
654
655 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200656
657 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200658 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300660 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200661 hci_dev_put(hdev);
662
Johan Hedbergaee9b212012-02-18 15:07:59 +0200663 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200664}
665
666static void mgmt_pending_free(struct pending_cmd *cmd)
667{
668 sock_put(cmd->sk);
669 kfree(cmd->param);
670 kfree(cmd);
671}
672
673static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
674 struct hci_dev *hdev,
675 void *data, u16 len)
676{
677 struct pending_cmd *cmd;
678
679 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
680 if (!cmd)
681 return NULL;
682
683 cmd->opcode = opcode;
684 cmd->index = hdev->id;
685
686 cmd->param = kmalloc(len, GFP_ATOMIC);
687 if (!cmd->param) {
688 kfree(cmd);
689 return NULL;
690 }
691
692 if (data)
693 memcpy(cmd->param, data, len);
694
695 cmd->sk = sk;
696 sock_hold(sk);
697
698 list_add(&cmd->list, &hdev->mgmt_pending);
699
700 return cmd;
701}
702
703static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
704 void (*cb)(struct pending_cmd *cmd, void *data),
705 void *data)
706{
707 struct list_head *p, *n;
708
709 list_for_each_safe(p, n, &hdev->mgmt_pending) {
710 struct pending_cmd *cmd;
711
712 cmd = list_entry(p, struct pending_cmd, list);
713
714 if (opcode > 0 && cmd->opcode != opcode)
715 continue;
716
717 cb(cmd, data);
718 }
719}
720
721static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
722{
723 struct pending_cmd *cmd;
724
725 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
726 if (cmd->opcode == opcode)
727 return cmd;
728 }
729
730 return NULL;
731}
732
733static void mgmt_pending_remove(struct pending_cmd *cmd)
734{
735 list_del(&cmd->list);
736 mgmt_pending_free(cmd);
737}
738
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200739static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200740{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200742
Johan Hedbergaee9b212012-02-18 15:07:59 +0200743 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
744 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200745}
746
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300747static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300749 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200750 struct hci_dev *hdev;
751 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200752 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Johan Hedberg03811012010-12-08 00:21:06 +0200754 BT_DBG("request for hci%u", index);
755
756 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
760 hdev = hci_dev_get(index);
761 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100767 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
768 cancel_delayed_work(&hdev->power_off);
769
770 if (cp->val) {
771 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
772 mgmt_powered(hdev, 1);
773 goto failed;
774 }
775 }
776
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200777 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200778 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200779 goto failed;
780 }
781
782 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200783 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
784 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200785 goto failed;
786 }
787
788 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
789 if (!cmd) {
790 err = -ENOMEM;
791 goto failed;
792 }
793
794 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200795 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200796 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200797 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200798
799 err = 0;
800
801failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300802 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 hci_dev_put(hdev);
804 return err;
805}
806
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200807static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
808 u16 data_len, struct sock *skip_sk)
809{
810 struct sk_buff *skb;
811 struct mgmt_hdr *hdr;
812
813 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
814 if (!skb)
815 return -ENOMEM;
816
817 hdr = (void *) skb_put(skb, sizeof(*hdr));
818 hdr->opcode = cpu_to_le16(event);
819 if (hdev)
820 hdr->index = cpu_to_le16(hdev->id);
821 else
822 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
823 hdr->len = cpu_to_le16(data_len);
824
825 if (data)
826 memcpy(skb_put(skb, data_len), data, data_len);
827
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100828 /* Time stamp */
829 __net_timestamp(skb);
830
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200831 hci_send_to_control(skb, skip_sk);
832 kfree_skb(skb);
833
834 return 0;
835}
836
837static int new_settings(struct hci_dev *hdev, struct sock *skip)
838{
839 __le32 ev;
840
841 ev = cpu_to_le32(get_current_settings(hdev));
842
843 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
844}
845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300846static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200847{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300848 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200849 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200850 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200851 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200852 u8 scan;
853 int err;
854
Johan Hedberg03811012010-12-08 00:21:06 +0200855 BT_DBG("request for hci%u", index);
856
857 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200858 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200860
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100861 timeout = get_unaligned_le16(&cp->timeout);
862 if (!cp->val && timeout > 0)
863 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_INVALID_PARAMS);
865
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200866 hdev = hci_dev_get(index);
867 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200868 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
869 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300871 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200872
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200873 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
875 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200876 goto failed;
877 }
878
879 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
880 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200881 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
882 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200883 goto failed;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
887 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
888 MGMT_STATUS_REJECTED);
889 goto failed;
890 }
891
892 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 bool changed = false;
894
895 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
896 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
897 changed = true;
898 }
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200901 if (err < 0)
902 goto failed;
903
904 if (changed)
905 err = new_settings(hdev, sk);
906
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200907 goto failed;
908 }
909
910 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100911 if (hdev->discov_timeout > 0) {
912 cancel_delayed_work(&hdev->discov_off);
913 hdev->discov_timeout = 0;
914 }
915
916 if (cp->val && timeout > 0) {
917 hdev->discov_timeout = timeout;
918 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
919 msecs_to_jiffies(hdev->discov_timeout * 1000));
920 }
921
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200922 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200923 goto failed;
924 }
925
926 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
927 if (!cmd) {
928 err = -ENOMEM;
929 goto failed;
930 }
931
932 scan = SCAN_PAGE;
933
934 if (cp->val)
935 scan |= SCAN_INQUIRY;
936 else
937 cancel_delayed_work(&hdev->discov_off);
938
939 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
940 if (err < 0)
941 mgmt_pending_remove(cmd);
942
Johan Hedberg03811012010-12-08 00:21:06 +0200943 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200944 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200945
946failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200948 hci_dev_put(hdev);
949
950 return err;
951}
952
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200954{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300955 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200956 struct hci_dev *hdev;
957 struct pending_cmd *cmd;
958 u8 scan;
959 int err;
960
Johan Hedberge41d8b42010-12-13 21:07:03 +0200961 BT_DBG("request for hci%u", index);
962
Johan Hedberg03811012010-12-08 00:21:06 +0200963 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
967 hdev = hci_dev_get(index);
968 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200969 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
970 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300972 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200974 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200975 bool changed = false;
976
977 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
978 changed = true;
979
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200980 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200982 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
984 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
985 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200986
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200987 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200988 if (err < 0)
989 goto failed;
990
991 if (changed)
992 err = new_settings(hdev, sk);
993
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
998 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200999 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
1000 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 goto failed;
1002 }
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001005 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 goto failed;
1007 }
1008
1009 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1010 if (!cmd) {
1011 err = -ENOMEM;
1012 goto failed;
1013 }
1014
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001015 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001017 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 scan = 0;
1019
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001020 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1021 hdev->discov_timeout > 0)
1022 cancel_delayed_work(&hdev->discov_off);
1023 }
1024
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1026 if (err < 0)
1027 mgmt_pending_remove(cmd);
1028
1029failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031 hci_dev_put(hdev);
1032
1033 return err;
1034}
1035
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001036static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001037{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001038 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001039 struct hci_dev *hdev;
1040 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042 BT_DBG("request for hci%u", index);
1043
1044 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001045 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
1048 hdev = hci_dev_get(index);
1049 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001053 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
1055 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001056 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001057 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001058 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001059
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001060 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001061 if (err < 0)
1062 goto failed;
1063
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001064 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
1066failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001067 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001068 hci_dev_put(hdev);
1069
1070 return err;
1071}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001072
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001073static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1074{
1075 struct mgmt_mode *cp = data;
1076 struct pending_cmd *cmd;
1077 struct hci_dev *hdev;
1078 uint8_t val;
1079 int err;
1080
1081 BT_DBG("request for hci%u", index);
1082
1083 if (len != sizeof(*cp))
1084 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1085 MGMT_STATUS_INVALID_PARAMS);
1086
1087 hdev = hci_dev_get(index);
1088 if (!hdev)
1089 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1090 MGMT_STATUS_INVALID_PARAMS);
1091
1092 hci_dev_lock(hdev);
1093
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001094 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001095 bool changed = false;
1096
1097 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1098 &hdev->dev_flags)) {
1099 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1100 changed = true;
1101 }
1102
1103 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1104 if (err < 0)
1105 goto failed;
1106
1107 if (changed)
1108 err = new_settings(hdev, sk);
1109
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001110 goto failed;
1111 }
1112
1113 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1114 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1115 MGMT_STATUS_BUSY);
1116 goto failed;
1117 }
1118
1119 val = !!cp->val;
1120
1121 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1122 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1123 goto failed;
1124 }
1125
1126 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1127 if (!cmd) {
1128 err = -ENOMEM;
1129 goto failed;
1130 }
1131
1132 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1133 if (err < 0) {
1134 mgmt_pending_remove(cmd);
1135 goto failed;
1136 }
1137
1138failed:
1139 hci_dev_unlock(hdev);
1140 hci_dev_put(hdev);
1141
1142 return err;
1143}
1144
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001145static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1146{
1147 struct mgmt_mode *cp = data;
1148 struct pending_cmd *cmd;
1149 struct hci_dev *hdev;
1150 uint8_t val;
1151 int err;
1152
1153 BT_DBG("request for hci%u", index);
1154
1155 if (len != sizeof(*cp))
1156 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hdev = hci_dev_get(index);
1160 if (!hdev)
1161 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1162 MGMT_STATUS_INVALID_PARAMS);
1163
1164 hci_dev_lock(hdev);
1165
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001166 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1167 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1168 MGMT_STATUS_NOT_SUPPORTED);
1169 goto failed;
1170 }
1171
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001172 val = !!cp->val;
1173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001174 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001175 bool changed = false;
1176
1177 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1178 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1179 changed = true;
1180 }
1181
1182 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1183 if (err < 0)
1184 goto failed;
1185
1186 if (changed)
1187 err = new_settings(hdev, sk);
1188
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001189 goto failed;
1190 }
1191
1192 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1193 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1194 goto failed;
1195 }
1196
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001197 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1198 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1199 goto failed;
1200 }
1201
1202 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1203 if (!cmd) {
1204 err = -ENOMEM;
1205 goto failed;
1206 }
1207
1208 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1209 if (err < 0) {
1210 mgmt_pending_remove(cmd);
1211 goto failed;
1212 }
1213
1214failed:
1215 hci_dev_unlock(hdev);
1216 hci_dev_put(hdev);
1217
1218 return err;
1219}
1220
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001221static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1222{
1223 struct mgmt_mode *cp = data;
1224 struct hci_dev *hdev;
1225 int err;
1226
1227 BT_DBG("request for hci%u", index);
1228
1229 if (len != sizeof(*cp))
1230 return cmd_status(sk, index, MGMT_OP_SET_HS,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
1233 hdev = hci_dev_get(index);
1234 if (!hdev)
1235 return cmd_status(sk, index, MGMT_OP_SET_HS,
1236 MGMT_STATUS_INVALID_PARAMS);
1237
1238 if (!enable_hs) {
1239 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1240 MGMT_STATUS_NOT_SUPPORTED);
1241 goto failed;
1242 }
1243
1244 if (cp->val)
1245 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1246 else
1247 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1248
1249 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1250
1251failed:
1252 hci_dev_put(hdev);
1253 return err;
1254}
1255
Johan Hedberg06199cf2012-02-22 16:37:11 +02001256static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1257{
1258 struct mgmt_mode *cp = data;
1259 struct hci_cp_write_le_host_supported hci_cp;
1260 struct pending_cmd *cmd;
1261 struct hci_dev *hdev;
1262 int err;
1263 u8 val;
1264
1265 BT_DBG("request for hci%u", index);
1266
1267 if (len != sizeof(*cp))
1268 return cmd_status(sk, index, MGMT_OP_SET_LE,
1269 MGMT_STATUS_INVALID_PARAMS);
1270
1271 hdev = hci_dev_get(index);
1272 if (!hdev)
1273 return cmd_status(sk, index, MGMT_OP_SET_LE,
1274 MGMT_STATUS_INVALID_PARAMS);
1275
1276 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1277 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1278 MGMT_STATUS_NOT_SUPPORTED);
1279 goto failed;
1280 }
1281
1282 val = !!cp->val;
1283
1284 if (!hdev_is_powered(hdev)) {
1285 bool changed = false;
1286
1287 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1288 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1289 changed = true;
1290 }
1291
1292 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1293 if (err < 0)
1294 goto failed;
1295
1296 if (changed)
1297 err = new_settings(hdev, sk);
1298
1299 goto failed;
1300 }
1301
1302 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1303 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1304 goto failed;
1305 }
1306
1307 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1308 if (!cmd) {
1309 err = -ENOMEM;
1310 goto failed;
1311 }
1312
1313 memset(&hci_cp, 0, sizeof(hci_cp));
1314
1315 if (val) {
1316 hci_cp.le = val;
1317 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1318 }
1319
1320 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1321 sizeof(hci_cp), &hci_cp);
1322 if (err < 0) {
1323 mgmt_pending_remove(cmd);
1324 goto failed;
1325 }
1326
1327failed:
1328 hci_dev_put(hdev);
1329 return err;
1330}
1331
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001332static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001334 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001335 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001336 struct hci_dev *hdev;
1337 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 int err;
1339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001342 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001343 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1344 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001345
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001348 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1349 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001351 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001353 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1354 err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
1355 MGMT_STATUS_BUSY);
1356 goto failed;
1357 }
1358
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1360 if (!uuid) {
1361 err = -ENOMEM;
1362 goto failed;
1363 }
1364
1365 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001366 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367
1368 list_add(&uuid->list, &hdev->uuids);
1369
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001370 err = update_class(hdev);
1371 if (err < 0)
1372 goto failed;
1373
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001374 err = update_eir(hdev);
1375 if (err < 0)
1376 goto failed;
1377
Johan Hedberg90e70452012-02-23 23:09:40 +02001378 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1379 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0,
1380 hdev->dev_class, 3);
1381 goto failed;
1382 }
1383
1384 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1385 if (!cmd) {
1386 err = -ENOMEM;
1387 goto failed;
1388 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389
1390failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001391 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001392 hci_dev_put(hdev);
1393
1394 return err;
1395}
1396
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001397static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001398{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001399 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001400 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001401 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001402 struct hci_dev *hdev;
1403 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 +02001404 int err, found;
1405
Szymon Janc4e51eae2011-02-25 19:05:48 +01001406 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001407
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001408 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001409 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1410 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001411
Szymon Janc4e51eae2011-02-25 19:05:48 +01001412 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001413 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001414 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1415 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001416
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001417 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001418
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001419 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1420 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1421 MGMT_STATUS_BUSY);
1422 goto unlock;
1423 }
1424
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001425 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1426 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001427
1428 if (hdev_is_powered(hdev) &&
1429 !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
1430 schedule_delayed_work(&hdev->service_cache,
1431 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1432
Johan Hedberg9246a862012-02-23 21:33:16 +02001433 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001434 }
1435
1436 found = 0;
1437
1438 list_for_each_safe(p, n, &hdev->uuids) {
1439 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1440
1441 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1442 continue;
1443
1444 list_del(&match->list);
1445 found++;
1446 }
1447
1448 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001449 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001451 goto unlock;
1452 }
1453
Johan Hedberg9246a862012-02-23 21:33:16 +02001454update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001455 err = update_class(hdev);
1456 if (err < 0)
1457 goto unlock;
1458
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001459 err = update_eir(hdev);
1460 if (err < 0)
1461 goto unlock;
1462
Johan Hedberg90e70452012-02-23 23:09:40 +02001463 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1464 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001465 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001466 goto unlock;
1467 }
1468
1469 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1470 if (!cmd) {
1471 err = -ENOMEM;
1472 goto unlock;
1473 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001474
1475unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001477 hci_dev_put(hdev);
1478
1479 return err;
1480}
1481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001482static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001483{
1484 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001485 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001486 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001487 int err;
1488
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001490
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001491 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001492 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1493 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001494
Szymon Janc4e51eae2011-02-25 19:05:48 +01001495 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001496 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001497 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1498 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001500 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001501
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001502 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1503 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1504 MGMT_STATUS_BUSY);
1505 goto unlock;
1506 }
1507
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001508 hdev->major_class = cp->major;
1509 hdev->minor_class = cp->minor;
1510
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001511 if (!hdev_is_powered(hdev)) {
1512 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1513 hdev->dev_class, 3);
1514 goto unlock;
1515 }
1516
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001517 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001518 hci_dev_unlock(hdev);
1519 cancel_delayed_work_sync(&hdev->service_cache);
1520 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001521 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001522 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001523
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001524 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001525 if (err < 0)
1526 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001527
Johan Hedberg90e70452012-02-23 23:09:40 +02001528 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001529 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001530 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001531 goto unlock;
1532 }
1533
1534 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1535 if (!cmd) {
1536 err = -ENOMEM;
1537 goto unlock;
1538 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001539
Johan Hedbergb5235a62012-02-21 14:32:24 +02001540unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001541 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001542 hci_dev_put(hdev);
1543
1544 return err;
1545}
1546
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001547static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001548{
1549 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001550 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001551 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001552 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001553
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001554 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001555 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1556 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001557
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558 key_count = get_unaligned_le16(&cp->key_count);
1559
Johan Hedberg86742e12011-11-07 23:13:38 +02001560 expected_len = sizeof(*cp) + key_count *
1561 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001562 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001563 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001564 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001565 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1566 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567 }
1568
Szymon Janc4e51eae2011-02-25 19:05:48 +01001569 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001570 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001571 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1572 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001573
Szymon Janc4e51eae2011-02-25 19:05:48 +01001574 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001575 key_count);
1576
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001578
1579 hci_link_keys_clear(hdev);
1580
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001581 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001582
1583 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001584 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001585 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001586 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001587
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001588 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001589 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001590
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001591 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1592 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001593 }
1594
Johan Hedbergaee9b212012-02-18 15:07:59 +02001595 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001597 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001598 hci_dev_put(hdev);
1599
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001600 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001601}
1602
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001603static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1604 u8 addr_type, struct sock *skip_sk)
1605{
1606 struct mgmt_ev_device_unpaired ev;
1607
1608 bacpy(&ev.addr.bdaddr, bdaddr);
1609 ev.addr.type = addr_type;
1610
1611 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1612 skip_sk);
1613}
1614
Johan Hedberg124f6e32012-02-09 13:50:12 +02001615static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001616{
1617 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001618 struct mgmt_cp_unpair_device *cp = data;
1619 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001620 struct hci_cp_disconnect dc;
1621 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001622 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001623 int err;
1624
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001625 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001626 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001627 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001628
Szymon Janc4e51eae2011-02-25 19:05:48 +01001629 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001630 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001631 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001635
Johan Hedberga8a1d192011-11-10 15:54:38 +02001636 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001637 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1638 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001639
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001640 if (!hdev_is_powered(hdev)) {
1641 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1642 MGMT_STATUS_NOT_POWERED,
1643 &rp, sizeof(rp));
1644 goto unlock;
1645 }
1646
Johan Hedberg124f6e32012-02-09 13:50:12 +02001647 if (cp->addr.type == MGMT_ADDR_BREDR)
1648 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1649 else
1650 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001651
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001652 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001653 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1654 MGMT_STATUS_NOT_PAIRED,
1655 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001656 goto unlock;
1657 }
1658
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001659 if (cp->disconnect) {
1660 if (cp->addr.type == MGMT_ADDR_BREDR)
1661 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1662 &cp->addr.bdaddr);
1663 else
1664 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1665 &cp->addr.bdaddr);
1666 } else {
1667 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001668 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001669
Johan Hedberga8a1d192011-11-10 15:54:38 +02001670 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001671 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001672 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001673 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001674 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001675 }
1676
Johan Hedberg124f6e32012-02-09 13:50:12 +02001677 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1678 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001679 if (!cmd) {
1680 err = -ENOMEM;
1681 goto unlock;
1682 }
1683
1684 put_unaligned_le16(conn->handle, &dc.handle);
1685 dc.reason = 0x13; /* Remote User Terminated Connection */
1686 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1687 if (err < 0)
1688 mgmt_pending_remove(cmd);
1689
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001690unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001692 hci_dev_put(hdev);
1693
1694 return err;
1695}
1696
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001697static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001698{
1699 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001700 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001701 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001702 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001703 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001704 int err;
1705
1706 BT_DBG("");
1707
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001708 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001709 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1710 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001711
Szymon Janc4e51eae2011-02-25 19:05:48 +01001712 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001713 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001714 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1715 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001716
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001717 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001718
1719 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001720 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1721 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001722 goto failed;
1723 }
1724
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001725 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001726 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1727 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001728 goto failed;
1729 }
1730
Johan Hedberg88c3df12012-02-09 14:27:38 +02001731 if (cp->addr.type == MGMT_ADDR_BREDR)
1732 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1733 else
1734 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001735
Johan Hedberg8962ee72011-01-20 12:40:27 +02001736 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001737 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1738 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001739 goto failed;
1740 }
1741
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001742 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001743 if (!cmd) {
1744 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001745 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001746 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001747
1748 put_unaligned_le16(conn->handle, &dc.handle);
1749 dc.reason = 0x13; /* Remote User Terminated Connection */
1750
1751 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1752 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001753 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001754
1755failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001756 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001757 hci_dev_put(hdev);
1758
1759 return err;
1760}
1761
Johan Hedberg48264f02011-11-09 13:58:58 +02001762static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001763{
1764 switch (link_type) {
1765 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001766 switch (addr_type) {
1767 case ADDR_LE_DEV_PUBLIC:
1768 return MGMT_ADDR_LE_PUBLIC;
1769 case ADDR_LE_DEV_RANDOM:
1770 return MGMT_ADDR_LE_RANDOM;
1771 default:
1772 return MGMT_ADDR_INVALID;
1773 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001774 case ACL_LINK:
1775 return MGMT_ADDR_BREDR;
1776 default:
1777 return MGMT_ADDR_INVALID;
1778 }
1779}
1780
Szymon Janc8ce62842011-03-01 16:55:32 +01001781static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001782{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001783 struct mgmt_rp_get_connections *rp;
1784 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001785 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001786 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001787 int err;
1788 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001789
1790 BT_DBG("");
1791
Szymon Janc4e51eae2011-02-25 19:05:48 +01001792 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001793 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001794 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1795 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001797 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001798
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001799 if (!hdev_is_powered(hdev)) {
1800 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1801 MGMT_STATUS_NOT_POWERED);
1802 goto unlock;
1803 }
1804
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001805 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001806 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1807 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001808 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001809 }
1810
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001811 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001812 rp = kmalloc(rp_len, GFP_ATOMIC);
1813 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001814 err = -ENOMEM;
1815 goto unlock;
1816 }
1817
Johan Hedberg2784eb42011-01-21 13:56:35 +02001818 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001819 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001820 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1821 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001822 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001823 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001824 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1825 continue;
1826 i++;
1827 }
1828
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001829 put_unaligned_le16(i, &rp->conn_count);
1830
Johan Hedberg4c659c32011-11-07 23:13:39 +02001831 /* Recalculate length in case of filtered SCO connections, etc */
1832 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001833
Johan Hedbergaee9b212012-02-18 15:07:59 +02001834 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001835
Johan Hedberga38528f2011-01-22 06:46:43 +02001836 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001837
1838unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001839 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001840 hci_dev_put(hdev);
1841 return err;
1842}
1843
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001844static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1845 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1846{
1847 struct pending_cmd *cmd;
1848 int err;
1849
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001850 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001851 sizeof(*cp));
1852 if (!cmd)
1853 return -ENOMEM;
1854
Johan Hedbergd8457692012-02-17 14:24:57 +02001855 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1856 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001857 if (err < 0)
1858 mgmt_pending_remove(cmd);
1859
1860 return err;
1861}
1862
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001863static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864{
1865 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001866 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001867 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001868 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001869 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001870 int err;
1871
1872 BT_DBG("");
1873
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001874 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001875 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1876 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001877
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001879 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001880 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1881 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001882
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001883 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001884
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001885 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001886 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1887 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001888 goto failed;
1889 }
1890
Johan Hedbergd8457692012-02-17 14:24:57 +02001891 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001892 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001893 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1894 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001895 goto failed;
1896 }
1897
1898 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001899 struct mgmt_cp_pin_code_neg_reply ncp;
1900
1901 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001902
1903 BT_ERR("PIN code is not 16 bytes long");
1904
1905 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1906 if (err >= 0)
1907 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001908 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001909
1910 goto failed;
1911 }
1912
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001913 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1914 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001915 if (!cmd) {
1916 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001917 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001918 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001919
Johan Hedbergd8457692012-02-17 14:24:57 +02001920 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001921 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001922 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001923
1924 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1925 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001926 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001927
1928failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001929 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001930 hci_dev_put(hdev);
1931
1932 return err;
1933}
1934
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001935static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001936{
1937 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001938 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001939 int err;
1940
1941 BT_DBG("");
1942
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001943 if (len != sizeof(*cp))
1944 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001945 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001946
Szymon Janc4e51eae2011-02-25 19:05:48 +01001947 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001948 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001949 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001950 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001951
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001952 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001953
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001954 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001955 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001956 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001957 goto failed;
1958 }
1959
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001960 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001961
1962failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001964 hci_dev_put(hdev);
1965
1966 return err;
1967}
1968
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001969static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001970{
1971 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001972 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001973
1974 BT_DBG("");
1975
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001976 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001977 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1978 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001979
Szymon Janc4e51eae2011-02-25 19:05:48 +01001980 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001981 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001982 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001986
1987 hdev->io_capability = cp->io_capability;
1988
1989 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001990 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001991
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001992 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001993 hci_dev_put(hdev);
1994
Johan Hedbergaee9b212012-02-18 15:07:59 +02001995 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001996}
1997
Johan Hedberge9a416b2011-02-19 12:05:56 -03001998static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1999{
2000 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002001 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002003 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002004 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2005 continue;
2006
Johan Hedberge9a416b2011-02-19 12:05:56 -03002007 if (cmd->user_data != conn)
2008 continue;
2009
2010 return cmd;
2011 }
2012
2013 return NULL;
2014}
2015
2016static void pairing_complete(struct pending_cmd *cmd, u8 status)
2017{
2018 struct mgmt_rp_pair_device rp;
2019 struct hci_conn *conn = cmd->user_data;
2020
Johan Hedbergba4e5642011-11-11 00:07:34 +02002021 bacpy(&rp.addr.bdaddr, &conn->dst);
2022 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002023
Johan Hedbergaee9b212012-02-18 15:07:59 +02002024 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
2025 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026
2027 /* So we don't get further callbacks for this connection */
2028 conn->connect_cfm_cb = NULL;
2029 conn->security_cfm_cb = NULL;
2030 conn->disconn_cfm_cb = NULL;
2031
2032 hci_conn_put(conn);
2033
Johan Hedberga664b5b2011-02-19 12:06:02 -03002034 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002035}
2036
2037static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2038{
2039 struct pending_cmd *cmd;
2040
2041 BT_DBG("status %u", status);
2042
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002043 cmd = find_pairing(conn);
2044 if (!cmd)
2045 BT_DBG("Unable to find a pending command");
2046 else
Johan Hedberge2113262012-02-18 15:20:03 +02002047 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002048}
2049
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002050static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002051{
2052 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002053 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002054 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002055 struct pending_cmd *cmd;
2056 u8 sec_level, auth_type;
2057 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002058 int err;
2059
2060 BT_DBG("");
2061
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002062 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002063 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2064 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002065
Szymon Janc4e51eae2011-02-25 19:05:48 +01002066 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002067 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002068 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2069 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002070
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002071 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002072
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002073 if (!hdev_is_powered(hdev)) {
2074 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2075 MGMT_STATUS_NOT_POWERED);
2076 goto unlock;
2077 }
2078
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002079 sec_level = BT_SECURITY_MEDIUM;
2080 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002081 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002082 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002083 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002084
Johan Hedbergba4e5642011-11-11 00:07:34 +02002085 if (cp->addr.type == MGMT_ADDR_BREDR)
2086 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002087 auth_type);
2088 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002089 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002090 auth_type);
2091
Johan Hedberg1425acb2011-11-11 00:07:35 +02002092 memset(&rp, 0, sizeof(rp));
2093 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2094 rp.addr.type = cp->addr.type;
2095
Ville Tervo30e76272011-02-22 16:10:53 -03002096 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002097 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2098 MGMT_STATUS_CONNECT_FAILED,
2099 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002100 goto unlock;
2101 }
2102
2103 if (conn->connect_cfm_cb) {
2104 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002105 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2106 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002107 goto unlock;
2108 }
2109
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002110 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002111 if (!cmd) {
2112 err = -ENOMEM;
2113 hci_conn_put(conn);
2114 goto unlock;
2115 }
2116
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002117 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002118 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002119 conn->connect_cfm_cb = pairing_complete_cb;
2120
Johan Hedberge9a416b2011-02-19 12:05:56 -03002121 conn->security_cfm_cb = pairing_complete_cb;
2122 conn->disconn_cfm_cb = pairing_complete_cb;
2123 conn->io_capability = cp->io_cap;
2124 cmd->user_data = conn;
2125
2126 if (conn->state == BT_CONNECTED &&
2127 hci_conn_security(conn, sec_level, auth_type))
2128 pairing_complete(cmd, 0);
2129
2130 err = 0;
2131
2132unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002133 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002134 hci_dev_put(hdev);
2135
2136 return err;
2137}
2138
Johan Hedberg28424702012-02-02 04:02:29 +02002139static int cancel_pair_device(struct sock *sk, u16 index,
2140 unsigned char *data, u16 len)
2141{
2142 struct mgmt_addr_info *addr = (void *) data;
2143 struct hci_dev *hdev;
2144 struct pending_cmd *cmd;
2145 struct hci_conn *conn;
2146 int err;
2147
2148 BT_DBG("");
2149
2150 if (len != sizeof(*addr))
2151 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2152 MGMT_STATUS_INVALID_PARAMS);
2153
2154 hdev = hci_dev_get(index);
2155 if (!hdev)
2156 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2157 MGMT_STATUS_INVALID_PARAMS);
2158
2159 hci_dev_lock(hdev);
2160
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002161 if (!hdev_is_powered(hdev)) {
2162 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2163 MGMT_STATUS_NOT_POWERED);
2164 goto unlock;
2165 }
2166
Johan Hedberg28424702012-02-02 04:02:29 +02002167 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2168 if (!cmd) {
2169 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2170 MGMT_STATUS_INVALID_PARAMS);
2171 goto unlock;
2172 }
2173
2174 conn = cmd->user_data;
2175
2176 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2177 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2178 MGMT_STATUS_INVALID_PARAMS);
2179 goto unlock;
2180 }
2181
2182 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2183
Johan Hedbergaee9b212012-02-18 15:07:59 +02002184 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002185 sizeof(*addr));
2186unlock:
2187 hci_dev_unlock(hdev);
2188 hci_dev_put(hdev);
2189
2190 return err;
2191}
2192
Brian Gix0df4c182011-11-16 13:53:13 -08002193static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002194 u8 type, u16 mgmt_op, u16 hci_op,
2195 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002196{
Johan Hedberga5c29682011-02-19 12:05:57 -03002197 struct pending_cmd *cmd;
2198 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002199 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002200 int err;
2201
Szymon Janc4e51eae2011-02-25 19:05:48 +01002202 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002203 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002204 return cmd_status(sk, index, mgmt_op,
2205 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002208
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002209 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002210 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2211 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002212 }
2213
Johan Hedberg272d90d2012-02-09 15:26:12 +02002214 if (type == MGMT_ADDR_BREDR)
2215 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2216 else
Brian Gix47c15e22011-11-16 13:53:14 -08002217 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002218
Johan Hedberg272d90d2012-02-09 15:26:12 +02002219 if (!conn) {
2220 err = cmd_status(sk, index, mgmt_op,
2221 MGMT_STATUS_NOT_CONNECTED);
2222 goto done;
2223 }
2224
2225 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002226 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002227 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002228
Brian Gix5fe57d92011-12-21 16:12:13 -08002229 if (!err)
2230 err = cmd_status(sk, index, mgmt_op,
2231 MGMT_STATUS_SUCCESS);
2232 else
2233 err = cmd_status(sk, index, mgmt_op,
2234 MGMT_STATUS_FAILED);
2235
Brian Gix47c15e22011-11-16 13:53:14 -08002236 goto done;
2237 }
2238
Brian Gix0df4c182011-11-16 13:53:13 -08002239 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002240 if (!cmd) {
2241 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002242 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002243 }
2244
Brian Gix0df4c182011-11-16 13:53:13 -08002245 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002246 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2247 struct hci_cp_user_passkey_reply cp;
2248
2249 bacpy(&cp.bdaddr, bdaddr);
2250 cp.passkey = passkey;
2251 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2252 } else
2253 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2254
Johan Hedberga664b5b2011-02-19 12:06:02 -03002255 if (err < 0)
2256 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002257
Brian Gix0df4c182011-11-16 13:53:13 -08002258done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002259 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002260 hci_dev_put(hdev);
2261
2262 return err;
2263}
2264
Brian Gix0df4c182011-11-16 13:53:13 -08002265static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002267 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002268
2269 BT_DBG("");
2270
2271 if (len != sizeof(*cp))
2272 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2273 MGMT_STATUS_INVALID_PARAMS);
2274
Johan Hedberg272d90d2012-02-09 15:26:12 +02002275 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2276 MGMT_OP_USER_CONFIRM_REPLY,
2277 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002278}
2279
2280static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2281 u16 len)
2282{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002283 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002284
2285 BT_DBG("");
2286
2287 if (len != sizeof(*cp))
2288 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2289 MGMT_STATUS_INVALID_PARAMS);
2290
Johan Hedberg272d90d2012-02-09 15:26:12 +02002291 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2292 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2293 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002294}
2295
Brian Gix604086b2011-11-23 08:28:33 -08002296static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2297{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002298 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002299
2300 BT_DBG("");
2301
2302 if (len != sizeof(*cp))
2303 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2304 EINVAL);
2305
Johan Hedberg272d90d2012-02-09 15:26:12 +02002306 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2307 MGMT_OP_USER_PASSKEY_REPLY,
2308 HCI_OP_USER_PASSKEY_REPLY,
2309 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002310}
2311
2312static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2313 u16 len)
2314{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002315 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002316
2317 BT_DBG("");
2318
2319 if (len != sizeof(*cp))
2320 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2321 EINVAL);
2322
Johan Hedberg272d90d2012-02-09 15:26:12 +02002323 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2324 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2325 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002326}
2327
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002328static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002329 u16 len)
2330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002331 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002332 struct hci_cp_write_local_name hci_cp;
2333 struct hci_dev *hdev;
2334 struct pending_cmd *cmd;
2335 int err;
2336
2337 BT_DBG("");
2338
2339 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002340 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2341 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002342
2343 hdev = hci_dev_get(index);
2344 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002345 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2346 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002347
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002349
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002350 memcpy(hdev->short_name, mgmt_cp->short_name,
2351 sizeof(hdev->short_name));
2352
Johan Hedbergb5235a62012-02-21 14:32:24 +02002353 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002354 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2355
2356 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2357 data, len);
2358 if (err < 0)
2359 goto failed;
2360
2361 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2362 sk);
2363
Johan Hedbergb5235a62012-02-21 14:32:24 +02002364 goto failed;
2365 }
2366
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002367 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002368 if (!cmd) {
2369 err = -ENOMEM;
2370 goto failed;
2371 }
2372
2373 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2374 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2375 &hci_cp);
2376 if (err < 0)
2377 mgmt_pending_remove(cmd);
2378
2379failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002381 hci_dev_put(hdev);
2382
2383 return err;
2384}
2385
Szymon Jancc35938b2011-03-22 13:12:21 +01002386static int read_local_oob_data(struct sock *sk, u16 index)
2387{
2388 struct hci_dev *hdev;
2389 struct pending_cmd *cmd;
2390 int err;
2391
2392 BT_DBG("hci%u", index);
2393
2394 hdev = hci_dev_get(index);
2395 if (!hdev)
2396 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002397 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002398
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002400
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002401 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002402 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002403 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002404 goto unlock;
2405 }
2406
2407 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2408 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002409 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002410 goto unlock;
2411 }
2412
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002413 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002414 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2415 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002416 goto unlock;
2417 }
2418
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002419 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002420 if (!cmd) {
2421 err = -ENOMEM;
2422 goto unlock;
2423 }
2424
2425 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2426 if (err < 0)
2427 mgmt_pending_remove(cmd);
2428
2429unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002430 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002431 hci_dev_put(hdev);
2432
2433 return err;
2434}
2435
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002436static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2437 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002438{
2439 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002440 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002441 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002442 int err;
2443
2444 BT_DBG("hci%u ", index);
2445
2446 if (len != sizeof(*cp))
2447 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002448 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002449
2450 hdev = hci_dev_get(index);
2451 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002452 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2453 MGMT_STATUS_INVALID_PARAMS,
2454 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002456 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002457
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002458 if (!hdev_is_powered(hdev)) {
2459 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2460 MGMT_STATUS_NOT_POWERED,
2461 &cp->addr, sizeof(cp->addr));
2462 goto unlock;
2463 }
2464
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002465 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002466 cp->randomizer);
2467 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002468 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002469 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002470 status = 0;
2471
2472 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2473 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002474
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002475unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002476 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002477 hci_dev_put(hdev);
2478
2479 return err;
2480}
2481
2482static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002483 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002484{
2485 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002486 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002487 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002488 int err;
2489
2490 BT_DBG("hci%u ", index);
2491
2492 if (len != sizeof(*cp))
2493 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002494 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002495
2496 hdev = hci_dev_get(index);
2497 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002498 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2499 MGMT_STATUS_INVALID_PARAMS,
2500 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002502 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002503
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002504 if (!hdev_is_powered(hdev)) {
2505 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2506 MGMT_STATUS_NOT_POWERED,
2507 &cp->addr, sizeof(cp->addr));
2508 goto unlock;
2509 }
2510
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002511 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002512 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002513 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002514 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002515 status = 0;
2516
2517 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2518 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002519
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002520unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002522 hci_dev_put(hdev);
2523
2524 return err;
2525}
2526
Andre Guedes5e0452c2012-02-17 20:39:38 -03002527static int discovery(struct hci_dev *hdev)
2528{
2529 int err;
2530
2531 if (lmp_host_le_capable(hdev)) {
2532 if (lmp_bredr_capable(hdev)) {
2533 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2534 LE_SCAN_INT, LE_SCAN_WIN,
2535 LE_SCAN_TIMEOUT_BREDR_LE);
2536 } else {
2537 hdev->discovery.type = DISCOV_TYPE_LE;
2538 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2539 LE_SCAN_INT, LE_SCAN_WIN,
2540 LE_SCAN_TIMEOUT_LE_ONLY);
2541 }
2542 } else {
2543 hdev->discovery.type = DISCOV_TYPE_BREDR;
2544 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2545 }
2546
2547 return err;
2548}
2549
2550int mgmt_interleaved_discovery(struct hci_dev *hdev)
2551{
2552 int err;
2553
2554 BT_DBG("%s", hdev->name);
2555
2556 hci_dev_lock(hdev);
2557
2558 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2559 if (err < 0)
2560 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2561
2562 hci_dev_unlock(hdev);
2563
2564 return err;
2565}
2566
Johan Hedberg450dfda2011-11-12 11:58:22 +02002567static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002571 struct pending_cmd *cmd;
2572 struct hci_dev *hdev;
2573 int err;
2574
2575 BT_DBG("hci%u", index);
2576
Johan Hedberg450dfda2011-11-12 11:58:22 +02002577 if (len != sizeof(*cp))
2578 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2579 MGMT_STATUS_INVALID_PARAMS);
2580
Johan Hedberg14a53662011-04-27 10:29:56 -04002581 hdev = hci_dev_get(index);
2582 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002583 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2584 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002585
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002586 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002587
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002588 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002589 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2590 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002591 goto failed;
2592 }
2593
Johan Hedbergff9ef572012-01-04 14:23:45 +02002594 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2595 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2596 MGMT_STATUS_BUSY);
2597 goto failed;
2598 }
2599
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002600 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002601 if (!cmd) {
2602 err = -ENOMEM;
2603 goto failed;
2604 }
2605
Andre Guedes4aab14e2012-02-17 20:39:36 -03002606 hdev->discovery.type = cp->type;
2607
2608 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002609 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002610 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002611 break;
2612
2613 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002614 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2615 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002616 break;
2617
Andre Guedes5e0452c2012-02-17 20:39:38 -03002618 case DISCOV_TYPE_INTERLEAVED:
2619 err = discovery(hdev);
2620 break;
2621
Andre Guedesf39799f2012-02-17 20:39:35 -03002622 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002623 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002624 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002625
Johan Hedberg14a53662011-04-27 10:29:56 -04002626 if (err < 0)
2627 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002628 else
2629 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002630
2631failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002633 hci_dev_put(hdev);
2634
2635 return err;
2636}
2637
Johan Hedbergd9306502012-02-20 23:25:18 +02002638static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002639{
Johan Hedbergd9306502012-02-20 23:25:18 +02002640 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002641 struct hci_dev *hdev;
2642 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002643 struct hci_cp_remote_name_req_cancel cp;
2644 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002645 int err;
2646
2647 BT_DBG("hci%u", index);
2648
Johan Hedbergd9306502012-02-20 23:25:18 +02002649 if (len != sizeof(*mgmt_cp))
2650 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2651 MGMT_STATUS_INVALID_PARAMS);
2652
Johan Hedberg14a53662011-04-27 10:29:56 -04002653 hdev = hci_dev_get(index);
2654 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002655 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2656 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002658 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002659
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002660 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002661 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2662 MGMT_STATUS_REJECTED,
2663 &mgmt_cp->type, sizeof(mgmt_cp->type));
2664 goto unlock;
2665 }
2666
2667 if (hdev->discovery.type != mgmt_cp->type) {
2668 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2669 MGMT_STATUS_INVALID_PARAMS,
2670 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002671 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002672 }
2673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002674 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002675 if (!cmd) {
2676 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002677 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002678 }
2679
Andre Guedes343f9352012-02-17 20:39:37 -03002680 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002681 err = hci_cancel_inquiry(hdev);
2682 if (err < 0)
2683 mgmt_pending_remove(cmd);
2684 else
2685 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2686 goto unlock;
2687 }
2688
2689 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2690 if (!e) {
2691 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002692 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002693 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002694 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2695 goto unlock;
2696 }
2697
2698 bacpy(&cp.bdaddr, &e->data.bdaddr);
2699 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2700 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002701 if (err < 0)
2702 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002703 else
2704 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002705
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002706unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002707 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002708 hci_dev_put(hdev);
2709
2710 return err;
2711}
2712
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002713static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002714{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002715 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002716 struct inquiry_entry *e;
2717 struct hci_dev *hdev;
2718 int err;
2719
2720 BT_DBG("hci%u", index);
2721
2722 if (len != sizeof(*cp))
2723 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2724 MGMT_STATUS_INVALID_PARAMS);
2725
2726 hdev = hci_dev_get(index);
2727 if (!hdev)
2728 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2729 MGMT_STATUS_INVALID_PARAMS);
2730
2731 hci_dev_lock(hdev);
2732
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002733 if (!hci_discovery_active(hdev)) {
2734 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2735 MGMT_STATUS_FAILED);
2736 goto failed;
2737 }
2738
Johan Hedberga198e7b2012-02-17 14:27:06 +02002739 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002740 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002741 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002742 MGMT_STATUS_INVALID_PARAMS);
2743 goto failed;
2744 }
2745
2746 if (cp->name_known) {
2747 e->name_state = NAME_KNOWN;
2748 list_del(&e->list);
2749 } else {
2750 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002751 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002752 }
2753
2754 err = 0;
2755
2756failed:
2757 hci_dev_unlock(hdev);
2758
2759 return err;
2760}
2761
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002762static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002763{
2764 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002765 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002766 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002767 int err;
2768
2769 BT_DBG("hci%u", index);
2770
Antti Julku7fbec222011-06-15 12:01:15 +03002771 if (len != sizeof(*cp))
2772 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002773 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002774
2775 hdev = hci_dev_get(index);
2776 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002777 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2778 MGMT_STATUS_INVALID_PARAMS,
2779 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002782
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002783 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002784 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002785 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002786 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002787 status = 0;
2788
2789 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2790 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002792 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002793 hci_dev_put(hdev);
2794
2795 return err;
2796}
2797
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002799{
2800 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002801 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002802 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002803 int err;
2804
2805 BT_DBG("hci%u", index);
2806
Antti Julku7fbec222011-06-15 12:01:15 +03002807 if (len != sizeof(*cp))
2808 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002809 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002810
2811 hdev = hci_dev_get(index);
2812 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002813 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2814 MGMT_STATUS_INVALID_PARAMS,
2815 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002817 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002818
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002819 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002820 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002821 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002822 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002823 status = 0;
2824
2825 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2826 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002827
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002828 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002829 hci_dev_put(hdev);
2830
2831 return err;
2832}
2833
Antti Julkuf6422ec2011-06-22 13:11:56 +03002834static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002835 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002836{
2837 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002839 struct hci_cp_write_page_scan_activity acp;
2840 u8 type;
2841 int err;
2842
2843 BT_DBG("hci%u", index);
2844
2845 if (len != sizeof(*cp))
2846 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002847 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002848
2849 hdev = hci_dev_get(index);
2850 if (!hdev)
2851 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002852 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002853 if (!hdev_is_powered(hdev))
2854 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2855 MGMT_STATUS_NOT_POWERED);
2856
2857 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2858 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2859 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002860
2861 hci_dev_lock(hdev);
2862
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002863 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002864 type = PAGE_SCAN_TYPE_INTERLACED;
2865 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2866 } else {
2867 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2868 acp.interval = 0x0800; /* default 1.28 sec page scan */
2869 }
2870
2871 acp.window = 0x0012; /* default 11.25 msec page scan window */
2872
2873 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2874 sizeof(acp), &acp);
2875 if (err < 0) {
2876 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002877 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002878 goto done;
2879 }
2880
2881 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2882 if (err < 0) {
2883 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002884 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002885 goto done;
2886 }
2887
Johan Hedbergaee9b212012-02-18 15:07:59 +02002888 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2889 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002890done:
2891 hci_dev_unlock(hdev);
2892 hci_dev_put(hdev);
2893
2894 return err;
2895}
2896
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002897static int load_long_term_keys(struct sock *sk, u16 index,
2898 void *cp_data, u16 len)
2899{
2900 struct hci_dev *hdev;
2901 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2902 u16 key_count, expected_len;
2903 int i;
2904
2905 if (len < sizeof(*cp))
2906 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2907 EINVAL);
2908
2909 key_count = get_unaligned_le16(&cp->key_count);
2910
2911 expected_len = sizeof(*cp) + key_count *
2912 sizeof(struct mgmt_ltk_info);
2913 if (expected_len != len) {
2914 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2915 len, expected_len);
2916 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2917 EINVAL);
2918 }
2919
2920 hdev = hci_dev_get(index);
2921 if (!hdev)
2922 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2923 ENODEV);
2924
2925 BT_DBG("hci%u key_count %u", index, key_count);
2926
2927 hci_dev_lock(hdev);
2928
2929 hci_smp_ltks_clear(hdev);
2930
2931 for (i = 0; i < key_count; i++) {
2932 struct mgmt_ltk_info *key = &cp->keys[i];
2933 u8 type;
2934
2935 if (key->master)
2936 type = HCI_SMP_LTK;
2937 else
2938 type = HCI_SMP_LTK_SLAVE;
2939
2940 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2941 type, 0, key->authenticated, key->val,
2942 key->enc_size, key->ediv, key->rand);
2943 }
2944
2945 hci_dev_unlock(hdev);
2946 hci_dev_put(hdev);
2947
2948 return 0;
2949}
2950
Johan Hedberg03811012010-12-08 00:21:06 +02002951int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2952{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002953 void *buf;
2954 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002955 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002956 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002957 int err;
2958
2959 BT_DBG("got %zu bytes", msglen);
2960
2961 if (msglen < sizeof(*hdr))
2962 return -EINVAL;
2963
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002964 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002965 if (!buf)
2966 return -ENOMEM;
2967
2968 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2969 err = -EFAULT;
2970 goto done;
2971 }
2972
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002973 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002974 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002975 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002976 len = get_unaligned_le16(&hdr->len);
2977
2978 if (len != msglen - sizeof(*hdr)) {
2979 err = -EINVAL;
2980 goto done;
2981 }
2982
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002983 cp = buf + sizeof(*hdr);
2984
Johan Hedberg03811012010-12-08 00:21:06 +02002985 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002986 case MGMT_OP_READ_VERSION:
2987 err = read_version(sk);
2988 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002989 case MGMT_OP_READ_COMMANDS:
2990 err = read_commands(sk);
2991 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002992 case MGMT_OP_READ_INDEX_LIST:
2993 err = read_index_list(sk);
2994 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002995 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002996 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002997 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002998 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002999 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003000 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003001 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003002 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02003003 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003004 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003005 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003006 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02003007 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003008 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02003009 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02003010 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003011 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02003012 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003013 case MGMT_OP_SET_LINK_SECURITY:
3014 err = set_link_security(sk, index, cp, len);
3015 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003016 case MGMT_OP_SET_SSP:
3017 err = set_ssp(sk, index, cp, len);
3018 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02003019 case MGMT_OP_SET_HS:
3020 err = set_hs(sk, index, cp, len);
3021 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003022 case MGMT_OP_SET_LE:
3023 err = set_le(sk, index, cp, len);
3024 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003025 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003026 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003027 break;
3028 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003029 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003030 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003031 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003032 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003033 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02003034 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003035 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003036 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003037 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003038 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003040 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01003041 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003042 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003043 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003044 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003045 break;
3046 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003047 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003048 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003049 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003050 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003051 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003052 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003053 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003054 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003055 case MGMT_OP_CANCEL_PAIR_DEVICE:
3056 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3057 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003058 case MGMT_OP_UNPAIR_DEVICE:
3059 err = unpair_device(sk, index, cp, len);
3060 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003061 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003062 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003063 break;
3064 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003066 break;
Brian Gix604086b2011-11-23 08:28:33 -08003067 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003068 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003069 break;
3070 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003071 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003072 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003073 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003074 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003075 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003076 case MGMT_OP_READ_LOCAL_OOB_DATA:
3077 err = read_local_oob_data(sk, index);
3078 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003079 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003080 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003081 break;
3082 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003083 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003084 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003085 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003086 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003087 break;
3088 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003089 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003090 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003091 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003092 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003093 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003094 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003095 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003096 break;
3097 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003098 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003099 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003100 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3101 err = load_long_term_keys(sk, index, cp, len);
3102 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003103 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003104 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003105 err = cmd_status(sk, index, opcode,
3106 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003107 break;
3108 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003109
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003110 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003111 goto done;
3112
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003113 err = msglen;
3114
3115done:
3116 kfree(buf);
3117 return err;
3118}
3119
Johan Hedbergb24752f2011-11-03 14:40:33 +02003120static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3121{
3122 u8 *status = data;
3123
3124 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3125 mgmt_pending_remove(cmd);
3126}
3127
Johan Hedberg744cf192011-11-08 20:40:14 +02003128int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003129{
Johan Hedberg744cf192011-11-08 20:40:14 +02003130 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003131}
3132
Johan Hedberg744cf192011-11-08 20:40:14 +02003133int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003134{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003135 u8 status = ENODEV;
3136
Johan Hedberg744cf192011-11-08 20:40:14 +02003137 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003138
Johan Hedberg744cf192011-11-08 20:40:14 +02003139 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003140}
3141
3142struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003143 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003144 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003145 u8 mgmt_status;
Johan Hedberg03811012010-12-08 00:21:06 +02003146};
3147
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003148static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003149{
Johan Hedberg03811012010-12-08 00:21:06 +02003150 struct cmd_lookup *match = data;
3151
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003152 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003153
3154 list_del(&cmd->list);
3155
3156 if (match->sk == NULL) {
3157 match->sk = cmd->sk;
3158 sock_hold(match->sk);
3159 }
3160
3161 mgmt_pending_free(cmd);
3162}
3163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003165{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003166 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003167 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003168
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003169 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3170 return 0;
3171
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003172 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003173
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003174 if (powered) {
3175 u8 scan = 0;
3176
3177 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3178 scan |= SCAN_PAGE;
3179 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3180 scan |= SCAN_INQUIRY;
3181
3182 if (scan)
3183 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003184
3185 update_class(hdev);
3186 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003187 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003188 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003189 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003190 }
3191
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003192 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003193
3194 if (match.sk)
3195 sock_put(match.sk);
3196
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003197 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003198}
3199
Johan Hedberg744cf192011-11-08 20:40:14 +02003200int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003201{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003202 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003203 bool changed = false;
3204 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003205
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003206 if (discoverable) {
3207 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3208 changed = true;
3209 } else {
3210 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3211 changed = true;
3212 }
Johan Hedberg03811012010-12-08 00:21:06 +02003213
Johan Hedberged9b5f22012-02-21 20:47:06 +02003214 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3215 &match);
3216
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003217 if (changed)
3218 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003219
Johan Hedberg03811012010-12-08 00:21:06 +02003220 if (match.sk)
3221 sock_put(match.sk);
3222
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003223 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003224}
3225
Johan Hedberg744cf192011-11-08 20:40:14 +02003226int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003227{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003228 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003229 bool changed = false;
3230 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003231
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003232 if (connectable) {
3233 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3234 changed = true;
3235 } else {
3236 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3237 changed = true;
3238 }
Johan Hedberg03811012010-12-08 00:21:06 +02003239
Johan Hedberged9b5f22012-02-21 20:47:06 +02003240 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3241 &match);
3242
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003243 if (changed)
3244 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003245
3246 if (match.sk)
3247 sock_put(match.sk);
3248
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003249 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003250}
3251
Johan Hedberg744cf192011-11-08 20:40:14 +02003252int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003253{
Johan Hedbergca69b792011-11-11 18:10:00 +02003254 u8 mgmt_err = mgmt_status(status);
3255
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003256 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003257 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003258 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003259
3260 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003261 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003262 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003263
3264 return 0;
3265}
3266
Johan Hedberg744cf192011-11-08 20:40:14 +02003267int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3268 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003269{
Johan Hedberg86742e12011-11-07 23:13:38 +02003270 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003271
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003272 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003273
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003274 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003275 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3276 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003277 ev.key.type = key->type;
3278 memcpy(ev.key.val, key->val, 16);
3279 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003280
Johan Hedberg744cf192011-11-08 20:40:14 +02003281 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003282}
Johan Hedbergf7520542011-01-20 12:34:39 +02003283
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003284int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3285{
3286 struct mgmt_ev_new_long_term_key ev;
3287
3288 memset(&ev, 0, sizeof(ev));
3289
3290 ev.store_hint = persistent;
3291 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3292 ev.key.addr.type = key->bdaddr_type;
3293 ev.key.authenticated = key->authenticated;
3294 ev.key.enc_size = key->enc_size;
3295 ev.key.ediv = key->ediv;
3296
3297 if (key->type == HCI_SMP_LTK)
3298 ev.key.master = 1;
3299
3300 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3301 memcpy(ev.key.val, key->val, sizeof(key->val));
3302
3303 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3304 &ev, sizeof(ev), NULL);
3305}
3306
Johan Hedbergafc747a2012-01-15 18:11:07 +02003307int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003308 u8 addr_type, u32 flags, u8 *name,
3309 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003310{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003311 char buf[512];
3312 struct mgmt_ev_device_connected *ev = (void *) buf;
3313 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003314
Johan Hedbergb644ba32012-01-17 21:48:47 +02003315 bacpy(&ev->addr.bdaddr, bdaddr);
3316 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003317
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003318 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003319
Johan Hedbergb644ba32012-01-17 21:48:47 +02003320 if (name_len > 0)
3321 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3322 name, name_len);
3323
3324 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3325 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3326 EIR_CLASS_OF_DEV, dev_class, 3);
3327
3328 put_unaligned_le16(eir_len, &ev->eir_len);
3329
3330 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3331 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003332}
3333
Johan Hedberg8962ee72011-01-20 12:40:27 +02003334static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3335{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003336 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003337 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003338 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003339
Johan Hedberg88c3df12012-02-09 14:27:38 +02003340 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3341 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003342
Johan Hedbergaee9b212012-02-18 15:07:59 +02003343 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3344 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003345
3346 *sk = cmd->sk;
3347 sock_hold(*sk);
3348
Johan Hedberga664b5b2011-02-19 12:06:02 -03003349 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003350}
3351
Johan Hedberg124f6e32012-02-09 13:50:12 +02003352static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003353{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003354 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003355 struct mgmt_cp_unpair_device *cp = cmd->param;
3356 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003357
3358 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003359 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3360 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003361
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003362 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3363
Johan Hedbergaee9b212012-02-18 15:07:59 +02003364 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003365
3366 mgmt_pending_remove(cmd);
3367}
3368
Johan Hedbergafc747a2012-01-15 18:11:07 +02003369int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3370 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003371{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003372 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003373 struct sock *sk = NULL;
3374 int err;
3375
Johan Hedberg744cf192011-11-08 20:40:14 +02003376 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003377
Johan Hedbergf7520542011-01-20 12:34:39 +02003378 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003379 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003380
Johan Hedbergafc747a2012-01-15 18:11:07 +02003381 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3382 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003383
3384 if (sk)
3385 sock_put(sk);
3386
Johan Hedberg124f6e32012-02-09 13:50:12 +02003387 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003388 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003389
Johan Hedberg8962ee72011-01-20 12:40:27 +02003390 return err;
3391}
3392
Johan Hedberg88c3df12012-02-09 14:27:38 +02003393int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3394 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003395{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003396 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003397 struct pending_cmd *cmd;
3398 int err;
3399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003400 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003401 if (!cmd)
3402 return -ENOENT;
3403
Johan Hedberg88c3df12012-02-09 14:27:38 +02003404 bacpy(&rp.addr.bdaddr, bdaddr);
3405 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003406
Johan Hedberg88c3df12012-02-09 14:27:38 +02003407 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003408 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003409
Johan Hedberga664b5b2011-02-19 12:06:02 -03003410 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003411
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003412 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3413 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003414 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003415}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003416
Johan Hedberg48264f02011-11-09 13:58:58 +02003417int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3418 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003419{
3420 struct mgmt_ev_connect_failed ev;
3421
Johan Hedberg4c659c32011-11-07 23:13:39 +02003422 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003423 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003424 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003425
Johan Hedberg744cf192011-11-08 20:40:14 +02003426 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003427}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003428
Johan Hedberg744cf192011-11-08 20:40:14 +02003429int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003430{
3431 struct mgmt_ev_pin_code_request ev;
3432
Johan Hedbergd8457692012-02-17 14:24:57 +02003433 bacpy(&ev.addr.bdaddr, bdaddr);
3434 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003435 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003436
Johan Hedberg744cf192011-11-08 20:40:14 +02003437 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003438 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003439}
3440
Johan Hedberg744cf192011-11-08 20:40:14 +02003441int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3442 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003443{
3444 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003445 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003446 int err;
3447
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003448 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003449 if (!cmd)
3450 return -ENOENT;
3451
Johan Hedbergd8457692012-02-17 14:24:57 +02003452 bacpy(&rp.addr.bdaddr, bdaddr);
3453 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003454
Johan Hedbergaee9b212012-02-18 15:07:59 +02003455 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3456 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003457
Johan Hedberga664b5b2011-02-19 12:06:02 -03003458 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003459
3460 return err;
3461}
3462
Johan Hedberg744cf192011-11-08 20:40:14 +02003463int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3464 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003465{
3466 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003467 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003468 int err;
3469
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003470 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003471 if (!cmd)
3472 return -ENOENT;
3473
Johan Hedbergd8457692012-02-17 14:24:57 +02003474 bacpy(&rp.addr.bdaddr, bdaddr);
3475 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003476
Johan Hedbergaee9b212012-02-18 15:07:59 +02003477 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3478 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003479
Johan Hedberga664b5b2011-02-19 12:06:02 -03003480 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003481
3482 return err;
3483}
Johan Hedberga5c29682011-02-19 12:05:57 -03003484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003486 u8 link_type, u8 addr_type, __le32 value,
3487 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003488{
3489 struct mgmt_ev_user_confirm_request ev;
3490
Johan Hedberg744cf192011-11-08 20:40:14 +02003491 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003492
Johan Hedberg272d90d2012-02-09 15:26:12 +02003493 bacpy(&ev.addr.bdaddr, bdaddr);
3494 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003495 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003496 put_unaligned_le32(value, &ev.value);
3497
Johan Hedberg744cf192011-11-08 20:40:14 +02003498 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003499 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003500}
3501
Johan Hedberg272d90d2012-02-09 15:26:12 +02003502int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3503 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003504{
3505 struct mgmt_ev_user_passkey_request ev;
3506
3507 BT_DBG("%s", hdev->name);
3508
Johan Hedberg272d90d2012-02-09 15:26:12 +02003509 bacpy(&ev.addr.bdaddr, bdaddr);
3510 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003511
3512 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3513 NULL);
3514}
3515
Brian Gix0df4c182011-11-16 13:53:13 -08003516static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003517 u8 link_type, u8 addr_type, u8 status,
3518 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003519{
3520 struct pending_cmd *cmd;
3521 struct mgmt_rp_user_confirm_reply rp;
3522 int err;
3523
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003524 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003525 if (!cmd)
3526 return -ENOENT;
3527
Johan Hedberg272d90d2012-02-09 15:26:12 +02003528 bacpy(&rp.addr.bdaddr, bdaddr);
3529 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003530 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3531 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003532
Johan Hedberga664b5b2011-02-19 12:06:02 -03003533 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003534
3535 return err;
3536}
3537
Johan Hedberg744cf192011-11-08 20:40:14 +02003538int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003539 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003540{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003541 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3542 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003543}
3544
Johan Hedberg272d90d2012-02-09 15:26:12 +02003545int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3546 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003547{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003548 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3549 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003550}
Johan Hedberg2a611692011-02-19 12:06:00 -03003551
Brian Gix604086b2011-11-23 08:28:33 -08003552int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003553 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003554{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003555 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3556 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003557}
3558
Johan Hedberg272d90d2012-02-09 15:26:12 +02003559int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3560 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003561{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003562 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3563 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003564}
3565
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003566int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3567 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003568{
3569 struct mgmt_ev_auth_failed ev;
3570
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003571 bacpy(&ev.addr.bdaddr, bdaddr);
3572 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003573 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003574
Johan Hedberg744cf192011-11-08 20:40:14 +02003575 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003576}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003577
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003578int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3579{
3580 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003581 bool changed = false;
3582 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003583
3584 if (status) {
3585 u8 mgmt_err = mgmt_status(status);
3586 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3587 cmd_status_rsp, &mgmt_err);
3588 return 0;
3589 }
3590
Johan Hedberg47990ea2012-02-22 11:58:37 +02003591 if (test_bit(HCI_AUTH, &hdev->flags)) {
3592 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3593 changed = true;
3594 } else {
3595 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3596 changed = true;
3597 }
3598
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003599 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3600 &match);
3601
Johan Hedberg47990ea2012-02-22 11:58:37 +02003602 if (changed)
3603 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003604
3605 if (match.sk)
3606 sock_put(match.sk);
3607
3608 return err;
3609}
3610
Johan Hedbergcacaf522012-02-21 00:52:42 +02003611static int clear_eir(struct hci_dev *hdev)
3612{
3613 struct hci_cp_write_eir cp;
3614
3615 if (!(hdev->features[6] & LMP_EXT_INQ))
3616 return 0;
3617
Johan Hedbergc80da272012-02-22 15:38:48 +02003618 memset(hdev->eir, 0, sizeof(hdev->eir));
3619
Johan Hedbergcacaf522012-02-21 00:52:42 +02003620 memset(&cp, 0, sizeof(cp));
3621
3622 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3623}
3624
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003625int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003626{
3627 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003628 bool changed = false;
3629 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003630
3631 if (status) {
3632 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003633
3634 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3635 &hdev->dev_flags))
3636 err = new_settings(hdev, NULL);
3637
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003638 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3639 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003640
3641 return err;
3642 }
3643
3644 if (enable) {
3645 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3646 changed = true;
3647 } else {
3648 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3649 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003650 }
3651
3652 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3653
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003654 if (changed)
3655 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003656
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003657 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003658 sock_put(match.sk);
3659
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003660 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3661 update_eir(hdev);
3662 else
3663 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003664
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003665 return err;
3666}
3667
Johan Hedberg90e70452012-02-23 23:09:40 +02003668static void class_rsp(struct pending_cmd *cmd, void *data)
3669{
3670 struct cmd_lookup *match = data;
3671
3672 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3673 match->hdev->dev_class, 3);
3674
3675 list_del(&cmd->list);
3676
3677 if (match->sk == NULL) {
3678 match->sk = cmd->sk;
3679 sock_hold(match->sk);
3680 }
3681
3682 mgmt_pending_free(cmd);
3683}
3684
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003685int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3686 u8 status)
3687{
Johan Hedberg90e70452012-02-23 23:09:40 +02003688 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3689 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003690
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003691 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3692
Johan Hedberg90e70452012-02-23 23:09:40 +02003693 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3694 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3695 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3696
3697 if (!status)
3698 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3699 dev_class, 3, NULL);
3700
3701 if (match.sk)
3702 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003703
3704 return err;
3705}
3706
Johan Hedberg744cf192011-11-08 20:40:14 +02003707int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003708{
3709 struct pending_cmd *cmd;
3710 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003711 bool changed = false;
3712 int err = 0;
3713
3714 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3715 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3716 changed = true;
3717 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003718
3719 memset(&ev, 0, sizeof(ev));
3720 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003721 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003722
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003723 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003724 if (!cmd)
3725 goto send_event;
3726
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003727 /* Always assume that either the short or the complete name has
3728 * changed if there was a pending mgmt command */
3729 changed = true;
3730
Johan Hedbergb312b1612011-03-16 14:29:37 +02003731 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003732 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003733 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003734 goto failed;
3735 }
3736
Johan Hedbergaee9b212012-02-18 15:07:59 +02003737 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003738 sizeof(ev));
3739 if (err < 0)
3740 goto failed;
3741
3742send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003743 if (changed)
3744 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3745 sizeof(ev), cmd ? cmd->sk : NULL);
3746
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003747 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003748
3749failed:
3750 if (cmd)
3751 mgmt_pending_remove(cmd);
3752 return err;
3753}
Szymon Jancc35938b2011-03-22 13:12:21 +01003754
Johan Hedberg744cf192011-11-08 20:40:14 +02003755int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3756 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003757{
3758 struct pending_cmd *cmd;
3759 int err;
3760
Johan Hedberg744cf192011-11-08 20:40:14 +02003761 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003762
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003763 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003764 if (!cmd)
3765 return -ENOENT;
3766
3767 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003768 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003769 MGMT_OP_READ_LOCAL_OOB_DATA,
3770 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003771 } else {
3772 struct mgmt_rp_read_local_oob_data rp;
3773
3774 memcpy(rp.hash, hash, sizeof(rp.hash));
3775 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3776
Johan Hedberg744cf192011-11-08 20:40:14 +02003777 err = cmd_complete(cmd->sk, hdev->id,
3778 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003779 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003780 }
3781
3782 mgmt_pending_remove(cmd);
3783
3784 return err;
3785}
Johan Hedberge17acd42011-03-30 23:57:16 +03003786
Johan Hedberg06199cf2012-02-22 16:37:11 +02003787int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3788{
3789 struct cmd_lookup match = { NULL, hdev };
3790 bool changed = false;
3791 int err = 0;
3792
3793 if (status) {
3794 u8 mgmt_err = mgmt_status(status);
3795
3796 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3797 &hdev->dev_flags))
3798 err = new_settings(hdev, NULL);
3799
3800 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3801 cmd_status_rsp, &mgmt_err);
3802
3803 return err;
3804 }
3805
3806 if (enable) {
3807 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3808 changed = true;
3809 } else {
3810 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3811 changed = true;
3812 }
3813
3814 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3815
3816 if (changed)
3817 err = new_settings(hdev, match.sk);
3818
3819 if (match.sk)
3820 sock_put(match.sk);
3821
3822 return err;
3823}
3824
Johan Hedberg48264f02011-11-09 13:58:58 +02003825int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003826 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003827 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003828{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003829 char buf[512];
3830 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003831 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003832
Johan Hedberg1dc06092012-01-15 21:01:23 +02003833 /* Leave 5 bytes for a potential CoD field */
3834 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003835 return -EINVAL;
3836
Johan Hedberg1dc06092012-01-15 21:01:23 +02003837 memset(buf, 0, sizeof(buf));
3838
Johan Hedberge319d2e2012-01-15 19:51:59 +02003839 bacpy(&ev->addr.bdaddr, bdaddr);
3840 ev->addr.type = link_to_mgmt(link_type, addr_type);
3841 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003842 if (cfm_name)
3843 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003844 if (!ssp)
3845 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003846
Johan Hedberg1dc06092012-01-15 21:01:23 +02003847 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003848 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003849
Johan Hedberg1dc06092012-01-15 21:01:23 +02003850 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3851 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3852 dev_class, 3);
3853
3854 put_unaligned_le16(eir_len, &ev->eir_len);
3855
3856 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003857
Johan Hedberge319d2e2012-01-15 19:51:59 +02003858 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003859}
Johan Hedberga88a9652011-03-30 13:18:12 +03003860
Johan Hedbergb644ba32012-01-17 21:48:47 +02003861int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3862 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003863{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003864 struct mgmt_ev_device_found *ev;
3865 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3866 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003867
Johan Hedbergb644ba32012-01-17 21:48:47 +02003868 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003869
Johan Hedbergb644ba32012-01-17 21:48:47 +02003870 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003871
Johan Hedbergb644ba32012-01-17 21:48:47 +02003872 bacpy(&ev->addr.bdaddr, bdaddr);
3873 ev->addr.type = link_to_mgmt(link_type, addr_type);
3874 ev->rssi = rssi;
3875
3876 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3877 name_len);
3878
3879 put_unaligned_le16(eir_len, &ev->eir_len);
3880
Johan Hedberg053c7e02012-02-04 00:06:00 +02003881 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3882 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003883}
Johan Hedberg314b2382011-04-27 10:29:57 -04003884
Andre Guedes7a135102011-11-09 17:14:25 -03003885int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003886{
3887 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003888 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003889 int err;
3890
Andre Guedes203159d2012-02-13 15:41:01 -03003891 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3892
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003893 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003894 if (!cmd)
3895 return -ENOENT;
3896
Johan Hedbergf808e162012-02-19 12:52:07 +02003897 type = hdev->discovery.type;
3898
3899 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3900 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003901 mgmt_pending_remove(cmd);
3902
3903 return err;
3904}
3905
Andre Guedese6d465c2011-11-09 17:14:26 -03003906int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3907{
3908 struct pending_cmd *cmd;
3909 int err;
3910
3911 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3912 if (!cmd)
3913 return -ENOENT;
3914
Johan Hedbergd9306502012-02-20 23:25:18 +02003915 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3916 &hdev->discovery.type,
3917 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003918 mgmt_pending_remove(cmd);
3919
3920 return err;
3921}
Johan Hedberg314b2382011-04-27 10:29:57 -04003922
Johan Hedberg744cf192011-11-08 20:40:14 +02003923int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003924{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003925 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003926 struct pending_cmd *cmd;
3927
Andre Guedes343fb142011-11-22 17:14:19 -03003928 BT_DBG("%s discovering %u", hdev->name, discovering);
3929
Johan Hedberg164a6e72011-11-01 17:06:44 +02003930 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003931 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003932 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003933 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003934
3935 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003936 u8 type = hdev->discovery.type;
3937
Johan Hedbergd9306502012-02-20 23:25:18 +02003938 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003939 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003940 mgmt_pending_remove(cmd);
3941 }
3942
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003943 memset(&ev, 0, sizeof(ev));
3944 ev.type = hdev->discovery.type;
3945 ev.discovering = discovering;
3946
3947 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003948}
Antti Julku5e762442011-08-25 16:48:02 +03003949
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003950int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003951{
3952 struct pending_cmd *cmd;
3953 struct mgmt_ev_device_blocked ev;
3954
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003955 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003956
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003957 bacpy(&ev.addr.bdaddr, bdaddr);
3958 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003959
Johan Hedberg744cf192011-11-08 20:40:14 +02003960 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3961 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003962}
3963
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003964int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003965{
3966 struct pending_cmd *cmd;
3967 struct mgmt_ev_device_unblocked ev;
3968
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003969 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003970
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003971 bacpy(&ev.addr.bdaddr, bdaddr);
3972 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003973
Johan Hedberg744cf192011-11-08 20:40:14 +02003974 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3975 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003976}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003977
3978module_param(enable_hs, bool, 0644);
3979MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3980
3981module_param(enable_le, bool, 0644);
3982MODULE_PARM_DESC(enable_le, "Enable Low Energy support");