blob: abf1adb8bc16dda869953c05ddce8b3179cede42 [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 Hedberg84bde9d2012-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 Hedberg84bde9d2012-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;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001078 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001079 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;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001150 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001151 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;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001263 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001264
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
Johan Hedberg1de028c2012-02-29 19:55:35 -08001276 hci_dev_lock(hdev);
1277
Johan Hedberg06199cf2012-02-22 16:37:11 +02001278 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1279 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1280 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001281 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001282 }
1283
1284 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001285 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001286
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001287 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001288 bool changed = false;
1289
1290 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1291 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1292 changed = true;
1293 }
1294
1295 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1296 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001297 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001298
1299 if (changed)
1300 err = new_settings(hdev, sk);
1301
Johan Hedberg1de028c2012-02-29 19:55:35 -08001302 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001303 }
1304
1305 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1306 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001307 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001308 }
1309
1310 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1311 if (!cmd) {
1312 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001313 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001314 }
1315
1316 memset(&hci_cp, 0, sizeof(hci_cp));
1317
1318 if (val) {
1319 hci_cp.le = val;
1320 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1321 }
1322
1323 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1324 sizeof(hci_cp), &hci_cp);
1325 if (err < 0) {
1326 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001327 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001328 }
1329
Johan Hedberg1de028c2012-02-29 19:55:35 -08001330unlock:
1331 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001332 hci_dev_put(hdev);
1333 return err;
1334}
1335
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001336static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001338 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001339 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340 struct hci_dev *hdev;
1341 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001342 int err;
1343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001345
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001346 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001347 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1348 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001349
Szymon Janc4e51eae2011-02-25 19:05:48 +01001350 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001352 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001354
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001355 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001356
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001357 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1358 err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
1359 MGMT_STATUS_BUSY);
1360 goto failed;
1361 }
1362
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001363 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1364 if (!uuid) {
1365 err = -ENOMEM;
1366 goto failed;
1367 }
1368
1369 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001370 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001371
1372 list_add(&uuid->list, &hdev->uuids);
1373
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001374 err = update_class(hdev);
1375 if (err < 0)
1376 goto failed;
1377
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001378 err = update_eir(hdev);
1379 if (err < 0)
1380 goto failed;
1381
Johan Hedberg90e70452012-02-23 23:09:40 +02001382 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1383 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0,
1384 hdev->dev_class, 3);
1385 goto failed;
1386 }
1387
1388 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1389 if (!cmd) {
1390 err = -ENOMEM;
1391 goto failed;
1392 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001393
1394failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001395 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001396 hci_dev_put(hdev);
1397
1398 return err;
1399}
1400
Johan Hedberg24b78d02012-02-23 23:24:30 +02001401static bool enable_service_cache(struct hci_dev *hdev)
1402{
1403 if (!hdev_is_powered(hdev))
1404 return false;
1405
1406 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1407 schedule_delayed_work(&hdev->service_cache,
1408 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1409 return true;
1410 }
1411
1412 return false;
1413}
1414
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001415static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001416{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001417 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001419 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001420 struct hci_dev *hdev;
1421 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 +02001422 int err, found;
1423
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001425
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001426 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001427 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1428 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001429
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001431 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001432 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1433 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001434
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001435 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001436
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001437 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1438 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1439 MGMT_STATUS_BUSY);
1440 goto unlock;
1441 }
1442
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001443 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1444 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001445
Johan Hedberg24b78d02012-02-23 23:24:30 +02001446 if (enable_service_cache(hdev)) {
1447 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1448 hdev->dev_class, 3);
1449 goto unlock;
1450 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001451
Johan Hedberg9246a862012-02-23 21:33:16 +02001452 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001453 }
1454
1455 found = 0;
1456
1457 list_for_each_safe(p, n, &hdev->uuids) {
1458 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1459
1460 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1461 continue;
1462
1463 list_del(&match->list);
1464 found++;
1465 }
1466
1467 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001468 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1469 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001470 goto unlock;
1471 }
1472
Johan Hedberg9246a862012-02-23 21:33:16 +02001473update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001474 err = update_class(hdev);
1475 if (err < 0)
1476 goto unlock;
1477
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001478 err = update_eir(hdev);
1479 if (err < 0)
1480 goto unlock;
1481
Johan Hedberg90e70452012-02-23 23:09:40 +02001482 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1483 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001484 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001485 goto unlock;
1486 }
1487
1488 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1489 if (!cmd) {
1490 err = -ENOMEM;
1491 goto unlock;
1492 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001493
1494unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001495 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001496 hci_dev_put(hdev);
1497
1498 return err;
1499}
1500
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001501static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001502{
1503 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001504 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001505 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001506 int err;
1507
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001509
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001510 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001511 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1512 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001513
Szymon Janc4e51eae2011-02-25 19:05:48 +01001514 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001515 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001516 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1517 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001519 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001520
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001521 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1522 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1523 MGMT_STATUS_BUSY);
1524 goto unlock;
1525 }
1526
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001527 hdev->major_class = cp->major;
1528 hdev->minor_class = cp->minor;
1529
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001530 if (!hdev_is_powered(hdev)) {
1531 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1532 hdev->dev_class, 3);
1533 goto unlock;
1534 }
1535
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001536 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001537 hci_dev_unlock(hdev);
1538 cancel_delayed_work_sync(&hdev->service_cache);
1539 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001540 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001541 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001542
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001543 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001544 if (err < 0)
1545 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001546
Johan Hedberg90e70452012-02-23 23:09:40 +02001547 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001548 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001549 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001550 goto unlock;
1551 }
1552
1553 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1554 if (!cmd) {
1555 err = -ENOMEM;
1556 goto unlock;
1557 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001558
Johan Hedbergb5235a62012-02-21 14:32:24 +02001559unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001560 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001561 hci_dev_put(hdev);
1562
1563 return err;
1564}
1565
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001566static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567{
1568 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001569 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001570 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001571 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001572
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001573 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001574 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1575 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001576
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577 key_count = get_unaligned_le16(&cp->key_count);
1578
Johan Hedberg86742e12011-11-07 23:13:38 +02001579 expected_len = sizeof(*cp) + key_count *
1580 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001581 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001582 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001583 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001584 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1585 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001586 }
1587
Szymon Janc4e51eae2011-02-25 19:05:48 +01001588 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001589 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001590 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1591 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001592
Szymon Janc4e51eae2011-02-25 19:05:48 +01001593 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001594 key_count);
1595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001596 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597
1598 hci_link_keys_clear(hdev);
1599
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001600 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001601
1602 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001603 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001604 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001605 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001606
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001607 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001608 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001609
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001610 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1611 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001612 }
1613
Johan Hedbergaee9b212012-02-18 15:07:59 +02001614 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001616 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001617 hci_dev_put(hdev);
1618
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001619 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001620}
1621
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001622static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1623 u8 addr_type, struct sock *skip_sk)
1624{
1625 struct mgmt_ev_device_unpaired ev;
1626
1627 bacpy(&ev.addr.bdaddr, bdaddr);
1628 ev.addr.type = addr_type;
1629
1630 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1631 skip_sk);
1632}
1633
Johan Hedberg124f6e32012-02-09 13:50:12 +02001634static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001635{
1636 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001637 struct mgmt_cp_unpair_device *cp = data;
1638 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001639 struct hci_cp_disconnect dc;
1640 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001641 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001642 int err;
1643
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001644 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001645 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001646 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001647
Szymon Janc4e51eae2011-02-25 19:05:48 +01001648 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001649 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001650 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001651 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001652
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001653 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001654
Johan Hedberga8a1d192011-11-10 15:54:38 +02001655 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001656 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1657 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001658
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001659 if (!hdev_is_powered(hdev)) {
1660 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1661 MGMT_STATUS_NOT_POWERED,
1662 &rp, sizeof(rp));
1663 goto unlock;
1664 }
1665
Johan Hedberg124f6e32012-02-09 13:50:12 +02001666 if (cp->addr.type == MGMT_ADDR_BREDR)
1667 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1668 else
1669 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001670
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001671 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001672 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1673 MGMT_STATUS_NOT_PAIRED,
1674 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001675 goto unlock;
1676 }
1677
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001678 if (cp->disconnect) {
1679 if (cp->addr.type == MGMT_ADDR_BREDR)
1680 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1681 &cp->addr.bdaddr);
1682 else
1683 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1684 &cp->addr.bdaddr);
1685 } else {
1686 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001687 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001688
Johan Hedberga8a1d192011-11-10 15:54:38 +02001689 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001690 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001691 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001692 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001693 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001694 }
1695
Johan Hedberg124f6e32012-02-09 13:50:12 +02001696 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1697 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001698 if (!cmd) {
1699 err = -ENOMEM;
1700 goto unlock;
1701 }
1702
1703 put_unaligned_le16(conn->handle, &dc.handle);
1704 dc.reason = 0x13; /* Remote User Terminated Connection */
1705 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1706 if (err < 0)
1707 mgmt_pending_remove(cmd);
1708
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001709unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001710 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001711 hci_dev_put(hdev);
1712
1713 return err;
1714}
1715
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001717{
1718 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001719 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001720 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001721 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001722 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001723 int err;
1724
1725 BT_DBG("");
1726
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001727 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001728 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1729 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001730
Szymon Janc4e51eae2011-02-25 19:05:48 +01001731 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001732 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001733 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1734 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001735
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001736 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001737
1738 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001739 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1740 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001741 goto failed;
1742 }
1743
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001744 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001745 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1746 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001747 goto failed;
1748 }
1749
Johan Hedberg88c3df12012-02-09 14:27:38 +02001750 if (cp->addr.type == MGMT_ADDR_BREDR)
1751 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1752 else
1753 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001754
Johan Hedberg8962ee72011-01-20 12:40:27 +02001755 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001756 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1757 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001758 goto failed;
1759 }
1760
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001761 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001762 if (!cmd) {
1763 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001764 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001765 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001766
1767 put_unaligned_le16(conn->handle, &dc.handle);
1768 dc.reason = 0x13; /* Remote User Terminated Connection */
1769
1770 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1771 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001772 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001773
1774failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001775 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001776 hci_dev_put(hdev);
1777
1778 return err;
1779}
1780
Johan Hedberg48264f02011-11-09 13:58:58 +02001781static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001782{
1783 switch (link_type) {
1784 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001785 switch (addr_type) {
1786 case ADDR_LE_DEV_PUBLIC:
1787 return MGMT_ADDR_LE_PUBLIC;
1788 case ADDR_LE_DEV_RANDOM:
1789 return MGMT_ADDR_LE_RANDOM;
1790 default:
1791 return MGMT_ADDR_INVALID;
1792 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001793 case ACL_LINK:
1794 return MGMT_ADDR_BREDR;
1795 default:
1796 return MGMT_ADDR_INVALID;
1797 }
1798}
1799
Szymon Janc8ce62842011-03-01 16:55:32 +01001800static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001801{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001802 struct mgmt_rp_get_connections *rp;
1803 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001804 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001805 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001806 int err;
1807 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001808
1809 BT_DBG("");
1810
Szymon Janc4e51eae2011-02-25 19:05:48 +01001811 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001812 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001813 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1814 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001815
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001816 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001817
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001818 if (!hdev_is_powered(hdev)) {
1819 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1820 MGMT_STATUS_NOT_POWERED);
1821 goto unlock;
1822 }
1823
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001824 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001825 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1826 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001827 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001828 }
1829
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001830 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001831 rp = kmalloc(rp_len, GFP_ATOMIC);
1832 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001833 err = -ENOMEM;
1834 goto unlock;
1835 }
1836
Johan Hedberg2784eb42011-01-21 13:56:35 +02001837 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001838 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001839 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1840 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001841 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001842 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001843 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1844 continue;
1845 i++;
1846 }
1847
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001848 put_unaligned_le16(i, &rp->conn_count);
1849
Johan Hedberg4c659c32011-11-07 23:13:39 +02001850 /* Recalculate length in case of filtered SCO connections, etc */
1851 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001852
Johan Hedbergaee9b212012-02-18 15:07:59 +02001853 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001854
Johan Hedberga38528f2011-01-22 06:46:43 +02001855 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001856
1857unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001858 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001859 hci_dev_put(hdev);
1860 return err;
1861}
1862
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001863static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1864 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1865{
1866 struct pending_cmd *cmd;
1867 int err;
1868
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001869 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001870 sizeof(*cp));
1871 if (!cmd)
1872 return -ENOMEM;
1873
Johan Hedbergd8457692012-02-17 14:24:57 +02001874 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1875 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001876 if (err < 0)
1877 mgmt_pending_remove(cmd);
1878
1879 return err;
1880}
1881
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001883{
1884 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001885 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001886 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001887 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001888 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 int err;
1890
1891 BT_DBG("");
1892
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001893 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001894 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1895 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001896
Szymon Janc4e51eae2011-02-25 19:05:48 +01001897 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001899 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1900 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001901
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001902 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001904 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001905 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1906 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001907 goto failed;
1908 }
1909
Johan Hedbergd8457692012-02-17 14:24:57 +02001910 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001911 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001912 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1913 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001914 goto failed;
1915 }
1916
1917 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001918 struct mgmt_cp_pin_code_neg_reply ncp;
1919
1920 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001921
1922 BT_ERR("PIN code is not 16 bytes long");
1923
1924 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1925 if (err >= 0)
1926 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001927 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001928
1929 goto failed;
1930 }
1931
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001932 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001933 if (!cmd) {
1934 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001935 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001936 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001937
Johan Hedbergd8457692012-02-17 14:24:57 +02001938 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001939 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001940 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001941
1942 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1943 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001944 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001945
1946failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001947 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001948 hci_dev_put(hdev);
1949
1950 return err;
1951}
1952
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001953static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001954{
1955 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001956 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001957 int err;
1958
1959 BT_DBG("");
1960
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001961 if (len != sizeof(*cp))
1962 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001963 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001964
Szymon Janc4e51eae2011-02-25 19:05:48 +01001965 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001966 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001967 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001968 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001969
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001970 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001971
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001972 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001973 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001974 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001975 goto failed;
1976 }
1977
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001978 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001979
1980failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001981 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001982 hci_dev_put(hdev);
1983
1984 return err;
1985}
1986
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001987static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001988{
1989 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001990 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001991
1992 BT_DBG("");
1993
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001994 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001995 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1996 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001997
Szymon Janc4e51eae2011-02-25 19:05:48 +01001998 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001999 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002000 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
2001 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002002
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002003 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002004
2005 hdev->io_capability = cp->io_capability;
2006
2007 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01002008 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002010 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002011 hci_dev_put(hdev);
2012
Johan Hedbergaee9b212012-02-18 15:07:59 +02002013 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002014}
2015
Johan Hedberge9a416b2011-02-19 12:05:56 -03002016static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
2017{
2018 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002019 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002020
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002021 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002022 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2023 continue;
2024
Johan Hedberge9a416b2011-02-19 12:05:56 -03002025 if (cmd->user_data != conn)
2026 continue;
2027
2028 return cmd;
2029 }
2030
2031 return NULL;
2032}
2033
2034static void pairing_complete(struct pending_cmd *cmd, u8 status)
2035{
2036 struct mgmt_rp_pair_device rp;
2037 struct hci_conn *conn = cmd->user_data;
2038
Johan Hedbergba4e5642011-11-11 00:07:34 +02002039 bacpy(&rp.addr.bdaddr, &conn->dst);
2040 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041
Johan Hedbergaee9b212012-02-18 15:07:59 +02002042 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
2043 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002044
2045 /* So we don't get further callbacks for this connection */
2046 conn->connect_cfm_cb = NULL;
2047 conn->security_cfm_cb = NULL;
2048 conn->disconn_cfm_cb = NULL;
2049
2050 hci_conn_put(conn);
2051
Johan Hedberga664b5b2011-02-19 12:06:02 -03002052 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002053}
2054
2055static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2056{
2057 struct pending_cmd *cmd;
2058
2059 BT_DBG("status %u", status);
2060
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002061 cmd = find_pairing(conn);
2062 if (!cmd)
2063 BT_DBG("Unable to find a pending command");
2064 else
Johan Hedberge2113262012-02-18 15:20:03 +02002065 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002066}
2067
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002068static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002069{
2070 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002071 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002072 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002073 struct pending_cmd *cmd;
2074 u8 sec_level, auth_type;
2075 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002076 int err;
2077
2078 BT_DBG("");
2079
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002080 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002081 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2082 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002083
Szymon Janc4e51eae2011-02-25 19:05:48 +01002084 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002085 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002086 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2087 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002090
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002091 if (!hdev_is_powered(hdev)) {
2092 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2093 MGMT_STATUS_NOT_POWERED);
2094 goto unlock;
2095 }
2096
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002097 sec_level = BT_SECURITY_MEDIUM;
2098 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002099 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002100 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002101 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002102
Johan Hedbergba4e5642011-11-11 00:07:34 +02002103 if (cp->addr.type == MGMT_ADDR_BREDR)
2104 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002105 auth_type);
2106 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002107 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002108 auth_type);
2109
Johan Hedberg1425acb2011-11-11 00:07:35 +02002110 memset(&rp, 0, sizeof(rp));
2111 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2112 rp.addr.type = cp->addr.type;
2113
Ville Tervo30e76272011-02-22 16:10:53 -03002114 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002115 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2116 MGMT_STATUS_CONNECT_FAILED,
2117 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002118 goto unlock;
2119 }
2120
2121 if (conn->connect_cfm_cb) {
2122 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002123 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2124 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002125 goto unlock;
2126 }
2127
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002128 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002129 if (!cmd) {
2130 err = -ENOMEM;
2131 hci_conn_put(conn);
2132 goto unlock;
2133 }
2134
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002135 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002136 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002137 conn->connect_cfm_cb = pairing_complete_cb;
2138
Johan Hedberge9a416b2011-02-19 12:05:56 -03002139 conn->security_cfm_cb = pairing_complete_cb;
2140 conn->disconn_cfm_cb = pairing_complete_cb;
2141 conn->io_capability = cp->io_cap;
2142 cmd->user_data = conn;
2143
2144 if (conn->state == BT_CONNECTED &&
2145 hci_conn_security(conn, sec_level, auth_type))
2146 pairing_complete(cmd, 0);
2147
2148 err = 0;
2149
2150unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002152 hci_dev_put(hdev);
2153
2154 return err;
2155}
2156
Johan Hedberg28424702012-02-02 04:02:29 +02002157static int cancel_pair_device(struct sock *sk, u16 index,
2158 unsigned char *data, u16 len)
2159{
2160 struct mgmt_addr_info *addr = (void *) data;
2161 struct hci_dev *hdev;
2162 struct pending_cmd *cmd;
2163 struct hci_conn *conn;
2164 int err;
2165
2166 BT_DBG("");
2167
2168 if (len != sizeof(*addr))
2169 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2170 MGMT_STATUS_INVALID_PARAMS);
2171
2172 hdev = hci_dev_get(index);
2173 if (!hdev)
2174 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2175 MGMT_STATUS_INVALID_PARAMS);
2176
2177 hci_dev_lock(hdev);
2178
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002179 if (!hdev_is_powered(hdev)) {
2180 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2181 MGMT_STATUS_NOT_POWERED);
2182 goto unlock;
2183 }
2184
Johan Hedberg28424702012-02-02 04:02:29 +02002185 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2186 if (!cmd) {
2187 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2188 MGMT_STATUS_INVALID_PARAMS);
2189 goto unlock;
2190 }
2191
2192 conn = cmd->user_data;
2193
2194 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2195 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2196 MGMT_STATUS_INVALID_PARAMS);
2197 goto unlock;
2198 }
2199
2200 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2201
Johan Hedbergaee9b212012-02-18 15:07:59 +02002202 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002203 sizeof(*addr));
2204unlock:
2205 hci_dev_unlock(hdev);
2206 hci_dev_put(hdev);
2207
2208 return err;
2209}
2210
Brian Gix0df4c182011-11-16 13:53:13 -08002211static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002212 u8 type, u16 mgmt_op, u16 hci_op,
2213 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002214{
Johan Hedberga5c29682011-02-19 12:05:57 -03002215 struct pending_cmd *cmd;
2216 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002217 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002218 int err;
2219
Szymon Janc4e51eae2011-02-25 19:05:48 +01002220 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002221 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002222 return cmd_status(sk, index, mgmt_op,
2223 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002224
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002225 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002226
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002227 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002228 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2229 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002230 }
2231
Johan Hedberg272d90d2012-02-09 15:26:12 +02002232 if (type == MGMT_ADDR_BREDR)
2233 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2234 else
Brian Gix47c15e22011-11-16 13:53:14 -08002235 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002236
Johan Hedberg272d90d2012-02-09 15:26:12 +02002237 if (!conn) {
2238 err = cmd_status(sk, index, mgmt_op,
2239 MGMT_STATUS_NOT_CONNECTED);
2240 goto done;
2241 }
2242
2243 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002244 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002245 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002246
Brian Gix5fe57d92011-12-21 16:12:13 -08002247 if (!err)
2248 err = cmd_status(sk, index, mgmt_op,
2249 MGMT_STATUS_SUCCESS);
2250 else
2251 err = cmd_status(sk, index, mgmt_op,
2252 MGMT_STATUS_FAILED);
2253
Brian Gix47c15e22011-11-16 13:53:14 -08002254 goto done;
2255 }
2256
Brian Gix0df4c182011-11-16 13:53:13 -08002257 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002258 if (!cmd) {
2259 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002260 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002261 }
2262
Brian Gix0df4c182011-11-16 13:53:13 -08002263 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002264 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2265 struct hci_cp_user_passkey_reply cp;
2266
2267 bacpy(&cp.bdaddr, bdaddr);
2268 cp.passkey = passkey;
2269 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2270 } else
2271 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2272
Johan Hedberga664b5b2011-02-19 12:06:02 -03002273 if (err < 0)
2274 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002275
Brian Gix0df4c182011-11-16 13:53:13 -08002276done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002277 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002278 hci_dev_put(hdev);
2279
2280 return err;
2281}
2282
Brian Gix0df4c182011-11-16 13:53:13 -08002283static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2284{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002286
2287 BT_DBG("");
2288
2289 if (len != sizeof(*cp))
2290 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2291 MGMT_STATUS_INVALID_PARAMS);
2292
Johan Hedberg272d90d2012-02-09 15:26:12 +02002293 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2294 MGMT_OP_USER_CONFIRM_REPLY,
2295 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002296}
2297
2298static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2299 u16 len)
2300{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002301 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002302
2303 BT_DBG("");
2304
2305 if (len != sizeof(*cp))
2306 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2307 MGMT_STATUS_INVALID_PARAMS);
2308
Johan Hedberg272d90d2012-02-09 15:26:12 +02002309 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2310 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2311 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002312}
2313
Brian Gix604086b2011-11-23 08:28:33 -08002314static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2315{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002316 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002317
2318 BT_DBG("");
2319
2320 if (len != sizeof(*cp))
2321 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2322 EINVAL);
2323
Johan Hedberg272d90d2012-02-09 15:26:12 +02002324 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2325 MGMT_OP_USER_PASSKEY_REPLY,
2326 HCI_OP_USER_PASSKEY_REPLY,
2327 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002328}
2329
2330static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2331 u16 len)
2332{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002333 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002334
2335 BT_DBG("");
2336
2337 if (len != sizeof(*cp))
2338 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2339 EINVAL);
2340
Johan Hedberg272d90d2012-02-09 15:26:12 +02002341 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2342 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2343 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002344}
2345
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002346static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002347 u16 len)
2348{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002349 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002350 struct hci_cp_write_local_name hci_cp;
2351 struct hci_dev *hdev;
2352 struct pending_cmd *cmd;
2353 int err;
2354
2355 BT_DBG("");
2356
2357 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002358 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2359 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002360
2361 hdev = hci_dev_get(index);
2362 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002363 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002365
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002366 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002367
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002368 memcpy(hdev->short_name, mgmt_cp->short_name,
2369 sizeof(hdev->short_name));
2370
Johan Hedbergb5235a62012-02-21 14:32:24 +02002371 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002372 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2373
2374 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2375 data, len);
2376 if (err < 0)
2377 goto failed;
2378
2379 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2380 sk);
2381
Johan Hedbergb5235a62012-02-21 14:32:24 +02002382 goto failed;
2383 }
2384
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002385 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002386 if (!cmd) {
2387 err = -ENOMEM;
2388 goto failed;
2389 }
2390
2391 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2392 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2393 &hci_cp);
2394 if (err < 0)
2395 mgmt_pending_remove(cmd);
2396
2397failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002398 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002399 hci_dev_put(hdev);
2400
2401 return err;
2402}
2403
Szymon Jancc35938b2011-03-22 13:12:21 +01002404static int read_local_oob_data(struct sock *sk, u16 index)
2405{
2406 struct hci_dev *hdev;
2407 struct pending_cmd *cmd;
2408 int err;
2409
2410 BT_DBG("hci%u", index);
2411
2412 hdev = hci_dev_get(index);
2413 if (!hdev)
2414 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002415 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002416
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002417 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002418
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002419 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002420 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002421 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002422 goto unlock;
2423 }
2424
2425 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2426 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002427 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002428 goto unlock;
2429 }
2430
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002431 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002432 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2433 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002434 goto unlock;
2435 }
2436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002437 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002438 if (!cmd) {
2439 err = -ENOMEM;
2440 goto unlock;
2441 }
2442
2443 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2444 if (err < 0)
2445 mgmt_pending_remove(cmd);
2446
2447unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002448 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002449 hci_dev_put(hdev);
2450
2451 return err;
2452}
2453
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002454static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2455 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002456{
2457 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002458 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002459 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002460 int err;
2461
2462 BT_DBG("hci%u ", index);
2463
2464 if (len != sizeof(*cp))
2465 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002466 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002467
2468 hdev = hci_dev_get(index);
2469 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002470 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2471 MGMT_STATUS_INVALID_PARAMS,
2472 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002475
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002476 if (!hdev_is_powered(hdev)) {
2477 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2478 MGMT_STATUS_NOT_POWERED,
2479 &cp->addr, sizeof(cp->addr));
2480 goto unlock;
2481 }
2482
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002483 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002484 cp->randomizer);
2485 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002486 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002487 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002488 status = 0;
2489
2490 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2491 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002492
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002493unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002494 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002495 hci_dev_put(hdev);
2496
2497 return err;
2498}
2499
2500static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002501 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002502{
2503 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002505 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002506 int err;
2507
2508 BT_DBG("hci%u ", index);
2509
2510 if (len != sizeof(*cp))
2511 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002512 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002513
2514 hdev = hci_dev_get(index);
2515 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002516 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2517 MGMT_STATUS_INVALID_PARAMS,
2518 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002519
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002520 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002521
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002522 if (!hdev_is_powered(hdev)) {
2523 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2524 MGMT_STATUS_NOT_POWERED,
2525 &cp->addr, sizeof(cp->addr));
2526 goto unlock;
2527 }
2528
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002529 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002530 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002531 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002532 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002533 status = 0;
2534
2535 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2536 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002537
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002538unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002539 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002540 hci_dev_put(hdev);
2541
2542 return err;
2543}
2544
Andre Guedes5e0452c2012-02-17 20:39:38 -03002545int mgmt_interleaved_discovery(struct hci_dev *hdev)
2546{
2547 int err;
2548
2549 BT_DBG("%s", hdev->name);
2550
2551 hci_dev_lock(hdev);
2552
2553 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2554 if (err < 0)
2555 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2556
2557 hci_dev_unlock(hdev);
2558
2559 return err;
2560}
2561
Johan Hedberg450dfda2011-11-12 11:58:22 +02002562static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002563 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002564{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002565 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002566 struct pending_cmd *cmd;
2567 struct hci_dev *hdev;
2568 int err;
2569
2570 BT_DBG("hci%u", index);
2571
Johan Hedberg450dfda2011-11-12 11:58:22 +02002572 if (len != sizeof(*cp))
2573 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2574 MGMT_STATUS_INVALID_PARAMS);
2575
Johan Hedberg14a53662011-04-27 10:29:56 -04002576 hdev = hci_dev_get(index);
2577 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002578 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2579 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002581 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002582
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002583 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002584 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2585 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002586 goto failed;
2587 }
2588
Johan Hedbergff9ef572012-01-04 14:23:45 +02002589 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2590 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2591 MGMT_STATUS_BUSY);
2592 goto failed;
2593 }
2594
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002595 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002596 if (!cmd) {
2597 err = -ENOMEM;
2598 goto failed;
2599 }
2600
Andre Guedes4aab14e2012-02-17 20:39:36 -03002601 hdev->discovery.type = cp->type;
2602
2603 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002604 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002605 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002606 break;
2607
2608 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002609 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2610 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002611 break;
2612
Andre Guedes5e0452c2012-02-17 20:39:38 -03002613 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002614 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2615 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2616 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2617 else
2618 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002619 break;
2620
Andre Guedesf39799f2012-02-17 20:39:35 -03002621 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002622 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002623 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002624
Johan Hedberg14a53662011-04-27 10:29:56 -04002625 if (err < 0)
2626 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002627 else
2628 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002629
2630failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002631 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002632 hci_dev_put(hdev);
2633
2634 return err;
2635}
2636
Johan Hedbergd9306502012-02-20 23:25:18 +02002637static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002638{
Johan Hedbergd9306502012-02-20 23:25:18 +02002639 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002640 struct hci_dev *hdev;
2641 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002642 struct hci_cp_remote_name_req_cancel cp;
2643 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002644 int err;
2645
2646 BT_DBG("hci%u", index);
2647
Johan Hedbergd9306502012-02-20 23:25:18 +02002648 if (len != sizeof(*mgmt_cp))
2649 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2650 MGMT_STATUS_INVALID_PARAMS);
2651
Johan Hedberg14a53662011-04-27 10:29:56 -04002652 hdev = hci_dev_get(index);
2653 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002654 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2655 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002656
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002657 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002658
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002659 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002660 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2661 MGMT_STATUS_REJECTED,
2662 &mgmt_cp->type, sizeof(mgmt_cp->type));
2663 goto unlock;
2664 }
2665
2666 if (hdev->discovery.type != mgmt_cp->type) {
2667 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2668 MGMT_STATUS_INVALID_PARAMS,
2669 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002670 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002671 }
2672
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002673 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002674 if (!cmd) {
2675 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002676 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002677 }
2678
Andre Guedes343f9352012-02-17 20:39:37 -03002679 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002680 err = hci_cancel_inquiry(hdev);
2681 if (err < 0)
2682 mgmt_pending_remove(cmd);
2683 else
2684 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2685 goto unlock;
2686 }
2687
2688 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2689 if (!e) {
2690 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002691 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002692 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002693 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2694 goto unlock;
2695 }
2696
2697 bacpy(&cp.bdaddr, &e->data.bdaddr);
2698 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2699 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002700 if (err < 0)
2701 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002702 else
2703 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002704
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002705unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002706 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002707 hci_dev_put(hdev);
2708
2709 return err;
2710}
2711
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002713{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002714 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002715 struct inquiry_entry *e;
2716 struct hci_dev *hdev;
2717 int err;
2718
2719 BT_DBG("hci%u", index);
2720
2721 if (len != sizeof(*cp))
2722 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2723 MGMT_STATUS_INVALID_PARAMS);
2724
2725 hdev = hci_dev_get(index);
2726 if (!hdev)
2727 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2728 MGMT_STATUS_INVALID_PARAMS);
2729
2730 hci_dev_lock(hdev);
2731
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002732 if (!hci_discovery_active(hdev)) {
2733 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2734 MGMT_STATUS_FAILED);
2735 goto failed;
2736 }
2737
Johan Hedberga198e7b2012-02-17 14:27:06 +02002738 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002739 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002740 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002741 MGMT_STATUS_INVALID_PARAMS);
2742 goto failed;
2743 }
2744
2745 if (cp->name_known) {
2746 e->name_state = NAME_KNOWN;
2747 list_del(&e->list);
2748 } else {
2749 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002750 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002751 }
2752
2753 err = 0;
2754
2755failed:
2756 hci_dev_unlock(hdev);
2757
2758 return err;
2759}
2760
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002761static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002762{
2763 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002764 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002765 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002766 int err;
2767
2768 BT_DBG("hci%u", index);
2769
Antti Julku7fbec222011-06-15 12:01:15 +03002770 if (len != sizeof(*cp))
2771 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002772 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002773
2774 hdev = hci_dev_get(index);
2775 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002776 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2777 MGMT_STATUS_INVALID_PARAMS,
2778 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002780 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002781
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002782 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002783 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002784 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002785 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002786 status = 0;
2787
2788 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2789 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002790
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002791 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002792 hci_dev_put(hdev);
2793
2794 return err;
2795}
2796
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002797static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002798{
2799 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002800 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002801 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002802 int err;
2803
2804 BT_DBG("hci%u", index);
2805
Antti Julku7fbec222011-06-15 12:01:15 +03002806 if (len != sizeof(*cp))
2807 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002808 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002809
2810 hdev = hci_dev_get(index);
2811 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002812 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2813 MGMT_STATUS_INVALID_PARAMS,
2814 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002815
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002816 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002817
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002818 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002819 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002820 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002821 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002822 status = 0;
2823
2824 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2825 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002827 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002828 hci_dev_put(hdev);
2829
2830 return err;
2831}
2832
Antti Julkuf6422ec2011-06-22 13:11:56 +03002833static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002834 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002835{
2836 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002838 struct hci_cp_write_page_scan_activity acp;
2839 u8 type;
2840 int err;
2841
2842 BT_DBG("hci%u", index);
2843
2844 if (len != sizeof(*cp))
2845 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002846 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002847
2848 hdev = hci_dev_get(index);
2849 if (!hdev)
2850 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002852 if (!hdev_is_powered(hdev))
2853 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2854 MGMT_STATUS_NOT_POWERED);
2855
2856 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2857 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2858 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002859
2860 hci_dev_lock(hdev);
2861
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002862 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002863 type = PAGE_SCAN_TYPE_INTERLACED;
2864 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2865 } else {
2866 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2867 acp.interval = 0x0800; /* default 1.28 sec page scan */
2868 }
2869
2870 acp.window = 0x0012; /* default 11.25 msec page scan window */
2871
2872 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2873 sizeof(acp), &acp);
2874 if (err < 0) {
2875 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002876 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002877 goto done;
2878 }
2879
2880 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2881 if (err < 0) {
2882 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002883 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002884 goto done;
2885 }
2886
Johan Hedbergaee9b212012-02-18 15:07:59 +02002887 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2888 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002889done:
2890 hci_dev_unlock(hdev);
2891 hci_dev_put(hdev);
2892
2893 return err;
2894}
2895
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002896static int load_long_term_keys(struct sock *sk, u16 index,
2897 void *cp_data, u16 len)
2898{
2899 struct hci_dev *hdev;
2900 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2901 u16 key_count, expected_len;
2902 int i;
2903
2904 if (len < sizeof(*cp))
2905 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2906 EINVAL);
2907
2908 key_count = get_unaligned_le16(&cp->key_count);
2909
2910 expected_len = sizeof(*cp) + key_count *
2911 sizeof(struct mgmt_ltk_info);
2912 if (expected_len != len) {
2913 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2914 len, expected_len);
2915 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2916 EINVAL);
2917 }
2918
2919 hdev = hci_dev_get(index);
2920 if (!hdev)
2921 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2922 ENODEV);
2923
2924 BT_DBG("hci%u key_count %u", index, key_count);
2925
2926 hci_dev_lock(hdev);
2927
2928 hci_smp_ltks_clear(hdev);
2929
2930 for (i = 0; i < key_count; i++) {
2931 struct mgmt_ltk_info *key = &cp->keys[i];
2932 u8 type;
2933
2934 if (key->master)
2935 type = HCI_SMP_LTK;
2936 else
2937 type = HCI_SMP_LTK_SLAVE;
2938
2939 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2940 type, 0, key->authenticated, key->val,
2941 key->enc_size, key->ediv, key->rand);
2942 }
2943
2944 hci_dev_unlock(hdev);
2945 hci_dev_put(hdev);
2946
2947 return 0;
2948}
2949
Johan Hedberg03811012010-12-08 00:21:06 +02002950int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2951{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002952 void *buf;
2953 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002954 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002955 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002956 int err;
2957
2958 BT_DBG("got %zu bytes", msglen);
2959
2960 if (msglen < sizeof(*hdr))
2961 return -EINVAL;
2962
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002963 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002964 if (!buf)
2965 return -ENOMEM;
2966
2967 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2968 err = -EFAULT;
2969 goto done;
2970 }
2971
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002972 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002973 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002974 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002975 len = get_unaligned_le16(&hdr->len);
2976
2977 if (len != msglen - sizeof(*hdr)) {
2978 err = -EINVAL;
2979 goto done;
2980 }
2981
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002982 cp = buf + sizeof(*hdr);
2983
Johan Hedberg03811012010-12-08 00:21:06 +02002984 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002985 case MGMT_OP_READ_VERSION:
2986 err = read_version(sk);
2987 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002988 case MGMT_OP_READ_COMMANDS:
2989 err = read_commands(sk);
2990 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002991 case MGMT_OP_READ_INDEX_LIST:
2992 err = read_index_list(sk);
2993 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002994 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002995 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002996 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002997 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002998 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002999 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003000 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003001 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02003002 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003003 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003004 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003005 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02003006 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003007 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02003008 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02003009 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02003011 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003012 case MGMT_OP_SET_LINK_SECURITY:
3013 err = set_link_security(sk, index, cp, len);
3014 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003015 case MGMT_OP_SET_SSP:
3016 err = set_ssp(sk, index, cp, len);
3017 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02003018 case MGMT_OP_SET_HS:
3019 err = set_hs(sk, index, cp, len);
3020 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003021 case MGMT_OP_SET_LE:
3022 err = set_le(sk, index, cp, len);
3023 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003024 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003025 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003026 break;
3027 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003028 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003029 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003030 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003031 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003032 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02003033 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003034 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003035 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003037 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003038 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003039 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01003040 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003041 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003042 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003043 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003044 break;
3045 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003046 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003047 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003048 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003049 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003050 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003051 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003052 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003053 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003054 case MGMT_OP_CANCEL_PAIR_DEVICE:
3055 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3056 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003057 case MGMT_OP_UNPAIR_DEVICE:
3058 err = unpair_device(sk, index, cp, len);
3059 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003060 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003061 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003062 break;
3063 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003064 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003065 break;
Brian Gix604086b2011-11-23 08:28:33 -08003066 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003067 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003068 break;
3069 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003070 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003071 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003072 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003073 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003074 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003075 case MGMT_OP_READ_LOCAL_OOB_DATA:
3076 err = read_local_oob_data(sk, index);
3077 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003078 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003079 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003080 break;
3081 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003082 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003083 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003084 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003085 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003086 break;
3087 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003088 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003089 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003090 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003091 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003092 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003093 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003094 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003095 break;
3096 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003097 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003098 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003099 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3100 err = load_long_term_keys(sk, index, cp, len);
3101 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003102 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003103 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003104 err = cmd_status(sk, index, opcode,
3105 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003106 break;
3107 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003108
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003109 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003110 goto done;
3111
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003112 err = msglen;
3113
3114done:
3115 kfree(buf);
3116 return err;
3117}
3118
Johan Hedbergb24752f2011-11-03 14:40:33 +02003119static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3120{
3121 u8 *status = data;
3122
3123 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3124 mgmt_pending_remove(cmd);
3125}
3126
Johan Hedberg744cf192011-11-08 20:40:14 +02003127int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003128{
Johan Hedberg744cf192011-11-08 20:40:14 +02003129 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003130}
3131
Johan Hedberg744cf192011-11-08 20:40:14 +02003132int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003133{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003134 u8 status = ENODEV;
3135
Johan Hedberg744cf192011-11-08 20:40:14 +02003136 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003137
Johan Hedberg744cf192011-11-08 20:40:14 +02003138 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003139}
3140
3141struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003142 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003143 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003144 u8 mgmt_status;
Johan Hedberg03811012010-12-08 00:21:06 +02003145};
3146
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003147static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003148{
Johan Hedberg03811012010-12-08 00:21:06 +02003149 struct cmd_lookup *match = data;
3150
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003151 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003152
3153 list_del(&cmd->list);
3154
3155 if (match->sk == NULL) {
3156 match->sk = cmd->sk;
3157 sock_hold(match->sk);
3158 }
3159
3160 mgmt_pending_free(cmd);
3161}
3162
Johan Hedberg744cf192011-11-08 20:40:14 +02003163int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003164{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003165 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003166 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003167
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003168 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3169 return 0;
3170
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003171 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003172
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003173 if (powered) {
3174 u8 scan = 0;
3175
3176 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3177 scan |= SCAN_PAGE;
3178 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3179 scan |= SCAN_INQUIRY;
3180
3181 if (scan)
3182 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003183
3184 update_class(hdev);
3185 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003186 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003187 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003188 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003189 }
3190
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003191 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003192
3193 if (match.sk)
3194 sock_put(match.sk);
3195
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003196 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003197}
3198
Johan Hedberg744cf192011-11-08 20:40:14 +02003199int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003200{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003201 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003202 bool changed = false;
3203 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003204
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003205 if (discoverable) {
3206 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3207 changed = true;
3208 } else {
3209 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3210 changed = true;
3211 }
Johan Hedberg03811012010-12-08 00:21:06 +02003212
Johan Hedberged9b5f22012-02-21 20:47:06 +02003213 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3214 &match);
3215
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003216 if (changed)
3217 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003218
Johan Hedberg03811012010-12-08 00:21:06 +02003219 if (match.sk)
3220 sock_put(match.sk);
3221
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003222 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003223}
3224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003226{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003227 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003228 bool changed = false;
3229 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003230
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003231 if (connectable) {
3232 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3233 changed = true;
3234 } else {
3235 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3236 changed = true;
3237 }
Johan Hedberg03811012010-12-08 00:21:06 +02003238
Johan Hedberged9b5f22012-02-21 20:47:06 +02003239 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3240 &match);
3241
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003242 if (changed)
3243 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003244
3245 if (match.sk)
3246 sock_put(match.sk);
3247
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003248 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003249}
3250
Johan Hedberg744cf192011-11-08 20:40:14 +02003251int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003252{
Johan Hedbergca69b792011-11-11 18:10:00 +02003253 u8 mgmt_err = mgmt_status(status);
3254
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003255 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003256 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003257 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003258
3259 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003260 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003261 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003262
3263 return 0;
3264}
3265
Johan Hedberg744cf192011-11-08 20:40:14 +02003266int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3267 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003268{
Johan Hedberg86742e12011-11-07 23:13:38 +02003269 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003270
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003271 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003272
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003273 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003274 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3275 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003276 ev.key.type = key->type;
3277 memcpy(ev.key.val, key->val, 16);
3278 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003279
Johan Hedberg744cf192011-11-08 20:40:14 +02003280 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003281}
Johan Hedbergf7520542011-01-20 12:34:39 +02003282
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003283int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3284{
3285 struct mgmt_ev_new_long_term_key ev;
3286
3287 memset(&ev, 0, sizeof(ev));
3288
3289 ev.store_hint = persistent;
3290 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3291 ev.key.addr.type = key->bdaddr_type;
3292 ev.key.authenticated = key->authenticated;
3293 ev.key.enc_size = key->enc_size;
3294 ev.key.ediv = key->ediv;
3295
3296 if (key->type == HCI_SMP_LTK)
3297 ev.key.master = 1;
3298
3299 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3300 memcpy(ev.key.val, key->val, sizeof(key->val));
3301
3302 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3303 &ev, sizeof(ev), NULL);
3304}
3305
Johan Hedbergafc747a2012-01-15 18:11:07 +02003306int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003307 u8 addr_type, u32 flags, u8 *name,
3308 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003309{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003310 char buf[512];
3311 struct mgmt_ev_device_connected *ev = (void *) buf;
3312 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003313
Johan Hedbergb644ba32012-01-17 21:48:47 +02003314 bacpy(&ev->addr.bdaddr, bdaddr);
3315 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003316
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003317 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003318
Johan Hedbergb644ba32012-01-17 21:48:47 +02003319 if (name_len > 0)
3320 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3321 name, name_len);
3322
3323 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3324 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3325 EIR_CLASS_OF_DEV, dev_class, 3);
3326
3327 put_unaligned_le16(eir_len, &ev->eir_len);
3328
3329 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3330 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003331}
3332
Johan Hedberg8962ee72011-01-20 12:40:27 +02003333static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3334{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003335 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003336 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003337 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003338
Johan Hedberg88c3df12012-02-09 14:27:38 +02003339 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3340 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003341
Johan Hedbergaee9b212012-02-18 15:07:59 +02003342 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3343 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003344
3345 *sk = cmd->sk;
3346 sock_hold(*sk);
3347
Johan Hedberga664b5b2011-02-19 12:06:02 -03003348 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003349}
3350
Johan Hedberg124f6e32012-02-09 13:50:12 +02003351static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003352{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003353 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003354 struct mgmt_cp_unpair_device *cp = cmd->param;
3355 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003356
3357 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003358 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3359 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003360
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003361 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3362
Johan Hedbergaee9b212012-02-18 15:07:59 +02003363 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003364
3365 mgmt_pending_remove(cmd);
3366}
3367
Johan Hedbergafc747a2012-01-15 18:11:07 +02003368int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3369 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003370{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003371 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003372 struct sock *sk = NULL;
3373 int err;
3374
Johan Hedberg744cf192011-11-08 20:40:14 +02003375 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003376
Johan Hedbergf7520542011-01-20 12:34:39 +02003377 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003378 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003379
Johan Hedbergafc747a2012-01-15 18:11:07 +02003380 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3381 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003382
3383 if (sk)
3384 sock_put(sk);
3385
Johan Hedberg124f6e32012-02-09 13:50:12 +02003386 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003387 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003388
Johan Hedberg8962ee72011-01-20 12:40:27 +02003389 return err;
3390}
3391
Johan Hedberg88c3df12012-02-09 14:27:38 +02003392int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3393 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003394{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003395 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003396 struct pending_cmd *cmd;
3397 int err;
3398
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003399 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003400 if (!cmd)
3401 return -ENOENT;
3402
Johan Hedberg88c3df12012-02-09 14:27:38 +02003403 bacpy(&rp.addr.bdaddr, bdaddr);
3404 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003405
Johan Hedberg88c3df12012-02-09 14:27:38 +02003406 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003407 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003408
Johan Hedberga664b5b2011-02-19 12:06:02 -03003409 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003410
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003411 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3412 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003413 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003414}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003415
Johan Hedberg48264f02011-11-09 13:58:58 +02003416int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3417 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003418{
3419 struct mgmt_ev_connect_failed ev;
3420
Johan Hedberg4c659c32011-11-07 23:13:39 +02003421 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003422 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003423 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003424
Johan Hedberg744cf192011-11-08 20:40:14 +02003425 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003426}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003427
Johan Hedberg744cf192011-11-08 20:40:14 +02003428int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003429{
3430 struct mgmt_ev_pin_code_request ev;
3431
Johan Hedbergd8457692012-02-17 14:24:57 +02003432 bacpy(&ev.addr.bdaddr, bdaddr);
3433 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003434 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003435
Johan Hedberg744cf192011-11-08 20:40:14 +02003436 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003437 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003438}
3439
Johan Hedberg744cf192011-11-08 20:40:14 +02003440int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3441 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003442{
3443 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003444 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003445 int err;
3446
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003447 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003448 if (!cmd)
3449 return -ENOENT;
3450
Johan Hedbergd8457692012-02-17 14:24:57 +02003451 bacpy(&rp.addr.bdaddr, bdaddr);
3452 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003453
Johan Hedbergaee9b212012-02-18 15:07:59 +02003454 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3455 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003456
Johan Hedberga664b5b2011-02-19 12:06:02 -03003457 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003458
3459 return err;
3460}
3461
Johan Hedberg744cf192011-11-08 20:40:14 +02003462int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3463 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003464{
3465 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003466 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003467 int err;
3468
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003469 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003470 if (!cmd)
3471 return -ENOENT;
3472
Johan Hedbergd8457692012-02-17 14:24:57 +02003473 bacpy(&rp.addr.bdaddr, bdaddr);
3474 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003475
Johan Hedbergaee9b212012-02-18 15:07:59 +02003476 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3477 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003478
Johan Hedberga664b5b2011-02-19 12:06:02 -03003479 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003480
3481 return err;
3482}
Johan Hedberga5c29682011-02-19 12:05:57 -03003483
Johan Hedberg744cf192011-11-08 20:40:14 +02003484int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003485 u8 link_type, u8 addr_type, __le32 value,
3486 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003487{
3488 struct mgmt_ev_user_confirm_request ev;
3489
Johan Hedberg744cf192011-11-08 20:40:14 +02003490 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003491
Johan Hedberg272d90d2012-02-09 15:26:12 +02003492 bacpy(&ev.addr.bdaddr, bdaddr);
3493 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003494 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003495 put_unaligned_le32(value, &ev.value);
3496
Johan Hedberg744cf192011-11-08 20:40:14 +02003497 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003498 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003499}
3500
Johan Hedberg272d90d2012-02-09 15:26:12 +02003501int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3502 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003503{
3504 struct mgmt_ev_user_passkey_request ev;
3505
3506 BT_DBG("%s", hdev->name);
3507
Johan Hedberg272d90d2012-02-09 15:26:12 +02003508 bacpy(&ev.addr.bdaddr, bdaddr);
3509 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003510
3511 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3512 NULL);
3513}
3514
Brian Gix0df4c182011-11-16 13:53:13 -08003515static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003516 u8 link_type, u8 addr_type, u8 status,
3517 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003518{
3519 struct pending_cmd *cmd;
3520 struct mgmt_rp_user_confirm_reply rp;
3521 int err;
3522
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003523 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003524 if (!cmd)
3525 return -ENOENT;
3526
Johan Hedberg272d90d2012-02-09 15:26:12 +02003527 bacpy(&rp.addr.bdaddr, bdaddr);
3528 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003529 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3530 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003531
Johan Hedberga664b5b2011-02-19 12:06:02 -03003532 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003533
3534 return err;
3535}
3536
Johan Hedberg744cf192011-11-08 20:40:14 +02003537int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003538 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003539{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003540 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3541 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003542}
3543
Johan Hedberg272d90d2012-02-09 15:26:12 +02003544int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3545 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003546{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003547 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3548 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003549}
Johan Hedberg2a611692011-02-19 12:06:00 -03003550
Brian Gix604086b2011-11-23 08:28:33 -08003551int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003552 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003553{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003554 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3555 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003556}
3557
Johan Hedberg272d90d2012-02-09 15:26:12 +02003558int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3559 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003560{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003561 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3562 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003563}
3564
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003565int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3566 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003567{
3568 struct mgmt_ev_auth_failed ev;
3569
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003570 bacpy(&ev.addr.bdaddr, bdaddr);
3571 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003572 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003573
Johan Hedberg744cf192011-11-08 20:40:14 +02003574 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003575}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003576
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003577int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3578{
3579 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003580 bool changed = false;
3581 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003582
3583 if (status) {
3584 u8 mgmt_err = mgmt_status(status);
3585 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3586 cmd_status_rsp, &mgmt_err);
3587 return 0;
3588 }
3589
Johan Hedberg47990ea2012-02-22 11:58:37 +02003590 if (test_bit(HCI_AUTH, &hdev->flags)) {
3591 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3592 changed = true;
3593 } else {
3594 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3595 changed = true;
3596 }
3597
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003598 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3599 &match);
3600
Johan Hedberg47990ea2012-02-22 11:58:37 +02003601 if (changed)
3602 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003603
3604 if (match.sk)
3605 sock_put(match.sk);
3606
3607 return err;
3608}
3609
Johan Hedbergcacaf522012-02-21 00:52:42 +02003610static int clear_eir(struct hci_dev *hdev)
3611{
3612 struct hci_cp_write_eir cp;
3613
3614 if (!(hdev->features[6] & LMP_EXT_INQ))
3615 return 0;
3616
Johan Hedbergc80da272012-02-22 15:38:48 +02003617 memset(hdev->eir, 0, sizeof(hdev->eir));
3618
Johan Hedbergcacaf522012-02-21 00:52:42 +02003619 memset(&cp, 0, sizeof(cp));
3620
3621 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3622}
3623
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003624int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003625{
3626 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003627 bool changed = false;
3628 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003629
3630 if (status) {
3631 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003632
3633 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3634 &hdev->dev_flags))
3635 err = new_settings(hdev, NULL);
3636
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003637 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3638 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003639
3640 return err;
3641 }
3642
3643 if (enable) {
3644 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3645 changed = true;
3646 } else {
3647 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3648 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003649 }
3650
3651 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3652
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003653 if (changed)
3654 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003655
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003656 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003657 sock_put(match.sk);
3658
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003659 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3660 update_eir(hdev);
3661 else
3662 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003663
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003664 return err;
3665}
3666
Johan Hedberg90e70452012-02-23 23:09:40 +02003667static void class_rsp(struct pending_cmd *cmd, void *data)
3668{
3669 struct cmd_lookup *match = data;
3670
3671 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3672 match->hdev->dev_class, 3);
3673
3674 list_del(&cmd->list);
3675
3676 if (match->sk == NULL) {
3677 match->sk = cmd->sk;
3678 sock_hold(match->sk);
3679 }
3680
3681 mgmt_pending_free(cmd);
3682}
3683
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003684int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3685 u8 status)
3686{
Johan Hedberg90e70452012-02-23 23:09:40 +02003687 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3688 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003689
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003690 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3691
Johan Hedberg90e70452012-02-23 23:09:40 +02003692 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3693 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3694 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3695
3696 if (!status)
3697 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3698 dev_class, 3, NULL);
3699
3700 if (match.sk)
3701 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003702
3703 return err;
3704}
3705
Johan Hedberg744cf192011-11-08 20:40:14 +02003706int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003707{
3708 struct pending_cmd *cmd;
3709 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003710 bool changed = false;
3711 int err = 0;
3712
3713 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3714 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3715 changed = true;
3716 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003717
3718 memset(&ev, 0, sizeof(ev));
3719 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003720 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003722 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003723 if (!cmd)
3724 goto send_event;
3725
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003726 /* Always assume that either the short or the complete name has
3727 * changed if there was a pending mgmt command */
3728 changed = true;
3729
Johan Hedbergb312b1612011-03-16 14:29:37 +02003730 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003731 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003732 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003733 goto failed;
3734 }
3735
Johan Hedbergaee9b212012-02-18 15:07:59 +02003736 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003737 sizeof(ev));
3738 if (err < 0)
3739 goto failed;
3740
3741send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003742 if (changed)
3743 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3744 sizeof(ev), cmd ? cmd->sk : NULL);
3745
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003746 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003747
3748failed:
3749 if (cmd)
3750 mgmt_pending_remove(cmd);
3751 return err;
3752}
Szymon Jancc35938b2011-03-22 13:12:21 +01003753
Johan Hedberg744cf192011-11-08 20:40:14 +02003754int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3755 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003756{
3757 struct pending_cmd *cmd;
3758 int err;
3759
Johan Hedberg744cf192011-11-08 20:40:14 +02003760 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003761
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003762 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003763 if (!cmd)
3764 return -ENOENT;
3765
3766 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003767 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003768 MGMT_OP_READ_LOCAL_OOB_DATA,
3769 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003770 } else {
3771 struct mgmt_rp_read_local_oob_data rp;
3772
3773 memcpy(rp.hash, hash, sizeof(rp.hash));
3774 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3775
Johan Hedberg744cf192011-11-08 20:40:14 +02003776 err = cmd_complete(cmd->sk, hdev->id,
3777 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003778 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003779 }
3780
3781 mgmt_pending_remove(cmd);
3782
3783 return err;
3784}
Johan Hedberge17acd42011-03-30 23:57:16 +03003785
Johan Hedberg06199cf2012-02-22 16:37:11 +02003786int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3787{
3788 struct cmd_lookup match = { NULL, hdev };
3789 bool changed = false;
3790 int err = 0;
3791
3792 if (status) {
3793 u8 mgmt_err = mgmt_status(status);
3794
3795 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3796 &hdev->dev_flags))
3797 err = new_settings(hdev, NULL);
3798
3799 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3800 cmd_status_rsp, &mgmt_err);
3801
3802 return err;
3803 }
3804
3805 if (enable) {
3806 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3807 changed = true;
3808 } else {
3809 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3810 changed = true;
3811 }
3812
3813 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3814
3815 if (changed)
3816 err = new_settings(hdev, match.sk);
3817
3818 if (match.sk)
3819 sock_put(match.sk);
3820
3821 return err;
3822}
3823
Johan Hedberg48264f02011-11-09 13:58:58 +02003824int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003825 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003826 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003827{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003828 char buf[512];
3829 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003830 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003831
Johan Hedberg1dc06092012-01-15 21:01:23 +02003832 /* Leave 5 bytes for a potential CoD field */
3833 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003834 return -EINVAL;
3835
Johan Hedberg1dc06092012-01-15 21:01:23 +02003836 memset(buf, 0, sizeof(buf));
3837
Johan Hedberge319d2e2012-01-15 19:51:59 +02003838 bacpy(&ev->addr.bdaddr, bdaddr);
3839 ev->addr.type = link_to_mgmt(link_type, addr_type);
3840 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003841 if (cfm_name)
3842 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003843 if (!ssp)
3844 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003845
Johan Hedberg1dc06092012-01-15 21:01:23 +02003846 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003847 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003848
Johan Hedberg1dc06092012-01-15 21:01:23 +02003849 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3850 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3851 dev_class, 3);
3852
3853 put_unaligned_le16(eir_len, &ev->eir_len);
3854
3855 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003856
Johan Hedberge319d2e2012-01-15 19:51:59 +02003857 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003858}
Johan Hedberga88a9652011-03-30 13:18:12 +03003859
Johan Hedbergb644ba32012-01-17 21:48:47 +02003860int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3861 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003862{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003863 struct mgmt_ev_device_found *ev;
3864 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3865 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003866
Johan Hedbergb644ba32012-01-17 21:48:47 +02003867 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003868
Johan Hedbergb644ba32012-01-17 21:48:47 +02003869 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003870
Johan Hedbergb644ba32012-01-17 21:48:47 +02003871 bacpy(&ev->addr.bdaddr, bdaddr);
3872 ev->addr.type = link_to_mgmt(link_type, addr_type);
3873 ev->rssi = rssi;
3874
3875 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3876 name_len);
3877
3878 put_unaligned_le16(eir_len, &ev->eir_len);
3879
Johan Hedberg053c7e02012-02-04 00:06:00 +02003880 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3881 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003882}
Johan Hedberg314b2382011-04-27 10:29:57 -04003883
Andre Guedes7a135102011-11-09 17:14:25 -03003884int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003885{
3886 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003887 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003888 int err;
3889
Andre Guedes203159d2012-02-13 15:41:01 -03003890 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3891
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003892 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003893 if (!cmd)
3894 return -ENOENT;
3895
Johan Hedbergf808e162012-02-19 12:52:07 +02003896 type = hdev->discovery.type;
3897
3898 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3899 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003900 mgmt_pending_remove(cmd);
3901
3902 return err;
3903}
3904
Andre Guedese6d465c2011-11-09 17:14:26 -03003905int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3906{
3907 struct pending_cmd *cmd;
3908 int err;
3909
3910 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3911 if (!cmd)
3912 return -ENOENT;
3913
Johan Hedbergd9306502012-02-20 23:25:18 +02003914 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3915 &hdev->discovery.type,
3916 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003917 mgmt_pending_remove(cmd);
3918
3919 return err;
3920}
Johan Hedberg314b2382011-04-27 10:29:57 -04003921
Johan Hedberg744cf192011-11-08 20:40:14 +02003922int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003923{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003924 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003925 struct pending_cmd *cmd;
3926
Andre Guedes343fb142011-11-22 17:14:19 -03003927 BT_DBG("%s discovering %u", hdev->name, discovering);
3928
Johan Hedberg164a6e72011-11-01 17:06:44 +02003929 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003930 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003931 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003932 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003933
3934 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003935 u8 type = hdev->discovery.type;
3936
Johan Hedbergd9306502012-02-20 23:25:18 +02003937 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003938 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003939 mgmt_pending_remove(cmd);
3940 }
3941
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003942 memset(&ev, 0, sizeof(ev));
3943 ev.type = hdev->discovery.type;
3944 ev.discovering = discovering;
3945
3946 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003947}
Antti Julku5e762442011-08-25 16:48:02 +03003948
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003949int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003950{
3951 struct pending_cmd *cmd;
3952 struct mgmt_ev_device_blocked ev;
3953
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003954 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003955
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003956 bacpy(&ev.addr.bdaddr, bdaddr);
3957 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003958
Johan Hedberg744cf192011-11-08 20:40:14 +02003959 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3960 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003961}
3962
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003963int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003964{
3965 struct pending_cmd *cmd;
3966 struct mgmt_ev_device_unblocked ev;
3967
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003968 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003969
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003970 bacpy(&ev.addr.bdaddr, bdaddr);
3971 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003972
Johan Hedberg744cf192011-11-08 20:40:14 +02003973 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3974 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003975}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003976
3977module_param(enable_hs, bool, 0644);
3978MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3979
3980module_param(enable_le, bool, 0644);
3981MODULE_PARM_DESC(enable_le, "Enable Low Energy support");