blob: 563190c9f7b0e714a18d11d08e1cd249183bfcf5 [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
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 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
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 if (!test_bit(HCI_UP, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200397
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 if (test_bit(HCI_PSCAN, &hdev->flags))
402 settings |= MGMT_SETTING_CONNECTABLE;
403
404 if (test_bit(HCI_ISCAN, &hdev->flags))
405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Andre Guedes59e29402011-12-30 10:34:03 -0300413 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
416 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
538 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];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200576 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577 return 0;
578
579 cod[0] = hdev->minor_class;
580 cod[1] = hdev->major_class;
581 cod[2] = get_service_classes(hdev);
582
583 if (memcmp(cod, hdev->dev_class, 3) == 0)
584 return 0;
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
587}
588
Johan Hedberg7d785252011-12-15 00:47:39 +0200589static void service_cache_off(struct work_struct *work)
590{
591 struct hci_dev *hdev = container_of(work, struct hci_dev,
592 service_cache.work);
593
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200594 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200595 return;
596
597 hci_dev_lock(hdev);
598
599 update_eir(hdev);
600 update_class(hdev);
601
602 hci_dev_unlock(hdev);
603}
604
605static void mgmt_init_hdev(struct hci_dev *hdev)
606{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200607 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200608 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 schedule_delayed_work(&hdev->service_cache,
612 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
613}
614
Johan Hedberg03811012010-12-08 00:21:06 +0200615static int read_controller_info(struct sock *sk, u16 index)
616{
617 struct mgmt_rp_read_info rp;
618 struct hci_dev *hdev;
619
620 BT_DBG("sock %p hci%u", sk, index);
621
622 hdev = hci_dev_get(index);
623 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200624 return cmd_status(sk, index, MGMT_OP_READ_INFO,
625 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300627 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200628
Johan Hedberg7d785252011-12-15 00:47:39 +0200629 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
630 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
632 memset(&rp, 0, sizeof(rp));
633
Johan Hedberg03811012010-12-08 00:21:06 +0200634 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200635
636 rp.version = hdev->hci_ver;
637
Johan Hedberg03811012010-12-08 00:21:06 +0200638 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200639
640 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
641 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
642
643 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200644
645 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
646
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300647 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200648 hci_dev_put(hdev);
649
Johan Hedbergaee9b212012-02-18 15:07:59 +0200650 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200651}
652
653static void mgmt_pending_free(struct pending_cmd *cmd)
654{
655 sock_put(cmd->sk);
656 kfree(cmd->param);
657 kfree(cmd);
658}
659
660static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
661 struct hci_dev *hdev,
662 void *data, u16 len)
663{
664 struct pending_cmd *cmd;
665
666 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
667 if (!cmd)
668 return NULL;
669
670 cmd->opcode = opcode;
671 cmd->index = hdev->id;
672
673 cmd->param = kmalloc(len, GFP_ATOMIC);
674 if (!cmd->param) {
675 kfree(cmd);
676 return NULL;
677 }
678
679 if (data)
680 memcpy(cmd->param, data, len);
681
682 cmd->sk = sk;
683 sock_hold(sk);
684
685 list_add(&cmd->list, &hdev->mgmt_pending);
686
687 return cmd;
688}
689
690static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
691 void (*cb)(struct pending_cmd *cmd, void *data),
692 void *data)
693{
694 struct list_head *p, *n;
695
696 list_for_each_safe(p, n, &hdev->mgmt_pending) {
697 struct pending_cmd *cmd;
698
699 cmd = list_entry(p, struct pending_cmd, list);
700
701 if (opcode > 0 && cmd->opcode != opcode)
702 continue;
703
704 cb(cmd, data);
705 }
706}
707
708static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
709{
710 struct pending_cmd *cmd;
711
712 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
713 if (cmd->opcode == opcode)
714 return cmd;
715 }
716
717 return NULL;
718}
719
720static void mgmt_pending_remove(struct pending_cmd *cmd)
721{
722 list_del(&cmd->list);
723 mgmt_pending_free(cmd);
724}
725
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200726static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200727{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200728 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200729
Johan Hedbergaee9b212012-02-18 15:07:59 +0200730 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
731 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200732}
733
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300734static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200735{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300736 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200737 struct hci_dev *hdev;
738 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200739 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200740
Johan Hedberg03811012010-12-08 00:21:06 +0200741 BT_DBG("request for hci%u", index);
742
743 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200744 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
745 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200746
747 hdev = hci_dev_get(index);
748 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300752 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100754 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
755 cancel_delayed_work(&hdev->power_off);
756
757 if (cp->val) {
758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
759 mgmt_powered(hdev, 1);
760 goto failed;
761 }
762 }
763
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 goto failed;
767 }
768
769 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200770 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
771 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
776 if (!cmd) {
777 err = -ENOMEM;
778 goto failed;
779 }
780
781 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200782 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200784 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
786 err = 0;
787
788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200790 hci_dev_put(hdev);
791 return err;
792}
793
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300794static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200795{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300796 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200797 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200798 struct pending_cmd *cmd;
799 u8 scan;
800 int err;
801
Johan Hedberg03811012010-12-08 00:21:06 +0200802 BT_DBG("request for hci%u", index);
803
804 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200805 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
806 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200808 hdev = hci_dev_get(index);
809 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200810 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300813 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200814
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200815 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200816 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
817 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200818 goto failed;
819 }
820
821 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
822 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200823 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
824 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200825 goto failed;
826 }
827
828 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
829 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200830 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200831 goto failed;
832 }
833
834 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
835 if (!cmd) {
836 err = -ENOMEM;
837 goto failed;
838 }
839
840 scan = SCAN_PAGE;
841
842 if (cp->val)
843 scan |= SCAN_INQUIRY;
844 else
845 cancel_delayed_work(&hdev->discov_off);
846
847 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
848 if (err < 0)
849 mgmt_pending_remove(cmd);
850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 if (cp->val)
852 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
853
Johan Hedberge41d8b42010-12-13 21:07:03 +0200854failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300855 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200856 hci_dev_put(hdev);
857
858 return err;
859}
860
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300861static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200862{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300863 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200864 struct hci_dev *hdev;
865 struct pending_cmd *cmd;
866 u8 scan;
867 int err;
868
Johan Hedberge41d8b42010-12-13 21:07:03 +0200869 BT_DBG("request for hci%u", index);
870
Johan Hedberg03811012010-12-08 00:21:06 +0200871 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200872 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
873 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200874
875 hdev = hci_dev_get(index);
876 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200877 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300880 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200881
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200882 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200883 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
884 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200885 goto failed;
886 }
887
888 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
889 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200890 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
891 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200892 goto failed;
893 }
894
895 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200896 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200897 goto failed;
898 }
899
900 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
901 if (!cmd) {
902 err = -ENOMEM;
903 goto failed;
904 }
905
906 if (cp->val)
907 scan = SCAN_PAGE;
908 else
909 scan = 0;
910
911 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
912 if (err < 0)
913 mgmt_pending_remove(cmd);
914
915failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300916 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200917 hci_dev_put(hdev);
918
919 return err;
920}
921
922static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
923 u16 data_len, struct sock *skip_sk)
924{
925 struct sk_buff *skb;
926 struct mgmt_hdr *hdr;
927
928 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
929 if (!skb)
930 return -ENOMEM;
931
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200932 hdr = (void *) skb_put(skb, sizeof(*hdr));
933 hdr->opcode = cpu_to_le16(event);
934 if (hdev)
935 hdr->index = cpu_to_le16(hdev->id);
936 else
937 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
938 hdr->len = cpu_to_le16(data_len);
939
940 if (data)
941 memcpy(skb_put(skb, data_len), data, data_len);
942
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100943 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944 kfree_skb(skb);
945
946 return 0;
947}
948
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300949static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200952 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200953 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200954 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200956 BT_DBG("request for hci%u", index);
957
958 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200959 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962 hdev = hci_dev_get(index);
963 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300967 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968
969 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200970 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200972 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200974 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200975 if (err < 0)
976 goto failed;
977
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981
982failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300983 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 hci_dev_put(hdev);
985
986 return err;
987}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200988
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200989static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
990{
991 struct mgmt_mode *cp = data;
992 struct pending_cmd *cmd;
993 struct hci_dev *hdev;
994 uint8_t val;
995 int err;
996
997 BT_DBG("request for hci%u", index);
998
999 if (len != sizeof(*cp))
1000 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1001 MGMT_STATUS_INVALID_PARAMS);
1002
1003 hdev = hci_dev_get(index);
1004 if (!hdev)
1005 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1006 MGMT_STATUS_INVALID_PARAMS);
1007
1008 hci_dev_lock(hdev);
1009
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001010 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001011 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1012 MGMT_STATUS_NOT_POWERED);
1013 goto failed;
1014 }
1015
1016 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1017 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1018 MGMT_STATUS_BUSY);
1019 goto failed;
1020 }
1021
1022 val = !!cp->val;
1023
1024 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1025 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1026 goto failed;
1027 }
1028
1029 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1030 if (!cmd) {
1031 err = -ENOMEM;
1032 goto failed;
1033 }
1034
1035 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1036 if (err < 0) {
1037 mgmt_pending_remove(cmd);
1038 goto failed;
1039 }
1040
1041failed:
1042 hci_dev_unlock(hdev);
1043 hci_dev_put(hdev);
1044
1045 return err;
1046}
1047
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001048static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1049{
1050 struct mgmt_mode *cp = data;
1051 struct pending_cmd *cmd;
1052 struct hci_dev *hdev;
1053 uint8_t val;
1054 int err;
1055
1056 BT_DBG("request for hci%u", index);
1057
1058 if (len != sizeof(*cp))
1059 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1060 MGMT_STATUS_INVALID_PARAMS);
1061
1062 hdev = hci_dev_get(index);
1063 if (!hdev)
1064 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1065 MGMT_STATUS_INVALID_PARAMS);
1066
1067 hci_dev_lock(hdev);
1068
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001069 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001070 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1071 MGMT_STATUS_NOT_POWERED);
1072 goto failed;
1073 }
1074
Johan Hedberg1e163572012-02-20 23:53:46 +02001075 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1076 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1077 MGMT_STATUS_NOT_SUPPORTED);
1078 goto failed;
1079 }
1080
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001081 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1082 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1083 goto failed;
1084 }
1085
1086 val = !!cp->val;
1087
1088 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1089 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1090 goto failed;
1091 }
1092
1093 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1094 if (!cmd) {
1095 err = -ENOMEM;
1096 goto failed;
1097 }
1098
1099 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1100 if (err < 0) {
1101 mgmt_pending_remove(cmd);
1102 goto failed;
1103 }
1104
1105failed:
1106 hci_dev_unlock(hdev);
1107 hci_dev_put(hdev);
1108
1109 return err;
1110}
1111
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001112static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1113{
1114 struct mgmt_mode *cp = data;
1115 struct hci_dev *hdev;
1116 int err;
1117
1118 BT_DBG("request for hci%u", index);
1119
1120 if (len != sizeof(*cp))
1121 return cmd_status(sk, index, MGMT_OP_SET_HS,
1122 MGMT_STATUS_INVALID_PARAMS);
1123
1124 hdev = hci_dev_get(index);
1125 if (!hdev)
1126 return cmd_status(sk, index, MGMT_OP_SET_HS,
1127 MGMT_STATUS_INVALID_PARAMS);
1128
1129 if (!enable_hs) {
1130 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1131 MGMT_STATUS_NOT_SUPPORTED);
1132 goto failed;
1133 }
1134
1135 if (cp->val)
1136 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1137 else
1138 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1139
1140 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1141
1142failed:
1143 hci_dev_put(hdev);
1144 return err;
1145}
1146
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001147static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001149 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001150 struct hci_dev *hdev;
1151 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001152 int err;
1153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001155
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001156 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001157 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1158 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001159
Szymon Janc4e51eae2011-02-25 19:05:48 +01001160 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001161 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1163 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001164
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001165 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001166
1167 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1168 if (!uuid) {
1169 err = -ENOMEM;
1170 goto failed;
1171 }
1172
1173 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001174 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001175
1176 list_add(&uuid->list, &hdev->uuids);
1177
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001178 err = update_class(hdev);
1179 if (err < 0)
1180 goto failed;
1181
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001182 err = update_eir(hdev);
1183 if (err < 0)
1184 goto failed;
1185
Johan Hedbergaee9b212012-02-18 15:07:59 +02001186 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001187
1188failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001189 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001190 hci_dev_put(hdev);
1191
1192 return err;
1193}
1194
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001195static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001197 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001198 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001199 struct hci_dev *hdev;
1200 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 +02001201 int err, found;
1202
Szymon Janc4e51eae2011-02-25 19:05:48 +01001203 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001204
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001205 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001206 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1207 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001208
Szymon Janc4e51eae2011-02-25 19:05:48 +01001209 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001210 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001211 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1212 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001214 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001215
1216 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1217 err = hci_uuids_clear(hdev);
1218 goto unlock;
1219 }
1220
1221 found = 0;
1222
1223 list_for_each_safe(p, n, &hdev->uuids) {
1224 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1225
1226 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1227 continue;
1228
1229 list_del(&match->list);
1230 found++;
1231 }
1232
1233 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001234 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1235 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236 goto unlock;
1237 }
1238
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001239 err = update_class(hdev);
1240 if (err < 0)
1241 goto unlock;
1242
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001243 err = update_eir(hdev);
1244 if (err < 0)
1245 goto unlock;
1246
Johan Hedbergaee9b212012-02-18 15:07:59 +02001247 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
1249unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001250 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001251 hci_dev_put(hdev);
1252
1253 return err;
1254}
1255
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001256static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001257{
1258 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001259 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001260 int err;
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001263
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001264 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001265 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1266 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001267
Szymon Janc4e51eae2011-02-25 19:05:48 +01001268 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001269 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001270 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1271 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001274
Johan Hedbergb5235a62012-02-21 14:32:24 +02001275 if (!hdev_is_powered(hdev)) {
1276 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1277 MGMT_STATUS_NOT_POWERED);
1278 goto unlock;
1279 }
1280
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001281 hdev->major_class = cp->major;
1282 hdev->minor_class = cp->minor;
1283
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001284 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001285 hci_dev_unlock(hdev);
1286 cancel_delayed_work_sync(&hdev->service_cache);
1287 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001288 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001289 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001290
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001291 err = update_class(hdev);
1292
1293 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001294 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1295 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001296
Johan Hedbergb5235a62012-02-21 14:32:24 +02001297unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001298 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001299 hci_dev_put(hdev);
1300
1301 return err;
1302}
1303
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001304static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001305{
1306 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001307 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001308 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001309 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001310
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001311 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001312 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1313 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001314
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001315 key_count = get_unaligned_le16(&cp->key_count);
1316
Johan Hedberg86742e12011-11-07 23:13:38 +02001317 expected_len = sizeof(*cp) + key_count *
1318 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001319 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001320 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001321 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001322 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1323 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001324 }
1325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001327 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001328 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001330
Szymon Janc4e51eae2011-02-25 19:05:48 +01001331 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001332 key_count);
1333
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001334 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001335
1336 hci_link_keys_clear(hdev);
1337
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001338 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001339
1340 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001341 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001342 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001343 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001344
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001345 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001346 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001347
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001348 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1349 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001350 }
1351
Johan Hedbergaee9b212012-02-18 15:07:59 +02001352 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001354 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001355 hci_dev_put(hdev);
1356
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001357 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001358}
1359
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001360static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1361 u8 addr_type, struct sock *skip_sk)
1362{
1363 struct mgmt_ev_device_unpaired ev;
1364
1365 bacpy(&ev.addr.bdaddr, bdaddr);
1366 ev.addr.type = addr_type;
1367
1368 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1369 skip_sk);
1370}
1371
Johan Hedberg124f6e32012-02-09 13:50:12 +02001372static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001373{
1374 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001375 struct mgmt_cp_unpair_device *cp = data;
1376 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001377 struct hci_cp_disconnect dc;
1378 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001379 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001380 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001381 int err;
1382
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001383 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001384 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001385 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001386
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001388 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001389 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001393
Johan Hedberga8a1d192011-11-10 15:54:38 +02001394 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001395 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1396 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001397
Johan Hedberg124f6e32012-02-09 13:50:12 +02001398 if (cp->addr.type == MGMT_ADDR_BREDR)
1399 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1400 else
1401 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001402
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001403 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001404 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001405 goto unlock;
1406 }
1407
Johan Hedberga8a1d192011-11-10 15:54:38 +02001408 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001409 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1410 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001411 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001412 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001413 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001414
Johan Hedberg124f6e32012-02-09 13:50:12 +02001415 if (cp->addr.type == MGMT_ADDR_BREDR)
1416 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1417 &cp->addr.bdaddr);
1418 else
1419 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1420 &cp->addr.bdaddr);
1421
Johan Hedberga8a1d192011-11-10 15:54:38 +02001422 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001423 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1424 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001425 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001426 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001427 }
1428
Johan Hedberg124f6e32012-02-09 13:50:12 +02001429 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1430 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001431 if (!cmd) {
1432 err = -ENOMEM;
1433 goto unlock;
1434 }
1435
1436 put_unaligned_le16(conn->handle, &dc.handle);
1437 dc.reason = 0x13; /* Remote User Terminated Connection */
1438 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1439 if (err < 0)
1440 mgmt_pending_remove(cmd);
1441
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001442unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001443 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001444 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1445 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001446 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001447 hci_dev_put(hdev);
1448
1449 return err;
1450}
1451
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001452static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001453{
1454 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001455 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001456 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001457 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001458 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001459 int err;
1460
1461 BT_DBG("");
1462
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001463 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001464 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1465 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001466
Szymon Janc4e51eae2011-02-25 19:05:48 +01001467 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001468 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001469 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1470 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001471
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001472 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001473
1474 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001475 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1476 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001477 goto failed;
1478 }
1479
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001480 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001481 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1482 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001483 goto failed;
1484 }
1485
Johan Hedberg88c3df12012-02-09 14:27:38 +02001486 if (cp->addr.type == MGMT_ADDR_BREDR)
1487 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1488 else
1489 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001490
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001492 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1493 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494 goto failed;
1495 }
1496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001497 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001498 if (!cmd) {
1499 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001500 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001501 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001502
1503 put_unaligned_le16(conn->handle, &dc.handle);
1504 dc.reason = 0x13; /* Remote User Terminated Connection */
1505
1506 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1507 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001508 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001509
1510failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001511 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001512 hci_dev_put(hdev);
1513
1514 return err;
1515}
1516
Johan Hedberg48264f02011-11-09 13:58:58 +02001517static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001518{
1519 switch (link_type) {
1520 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001521 switch (addr_type) {
1522 case ADDR_LE_DEV_PUBLIC:
1523 return MGMT_ADDR_LE_PUBLIC;
1524 case ADDR_LE_DEV_RANDOM:
1525 return MGMT_ADDR_LE_RANDOM;
1526 default:
1527 return MGMT_ADDR_INVALID;
1528 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001529 case ACL_LINK:
1530 return MGMT_ADDR_BREDR;
1531 default:
1532 return MGMT_ADDR_INVALID;
1533 }
1534}
1535
Szymon Janc8ce62842011-03-01 16:55:32 +01001536static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001537{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001538 struct mgmt_rp_get_connections *rp;
1539 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001540 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001541 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001542 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001543 int i, err;
1544
1545 BT_DBG("");
1546
Szymon Janc4e51eae2011-02-25 19:05:48 +01001547 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001548 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001549 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1550 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001552 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001553
1554 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001555 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1556 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1557 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001558 }
1559
Johan Hedberg4c659c32011-11-07 23:13:39 +02001560 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001561 rp = kmalloc(rp_len, GFP_ATOMIC);
1562 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001563 err = -ENOMEM;
1564 goto unlock;
1565 }
1566
Johan Hedberg2784eb42011-01-21 13:56:35 +02001567 put_unaligned_le16(count, &rp->conn_count);
1568
Johan Hedberg2784eb42011-01-21 13:56:35 +02001569 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001570 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001571 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1572 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001573 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001574 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001575 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1576 continue;
1577 i++;
1578 }
1579
1580 /* Recalculate length in case of filtered SCO connections, etc */
1581 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001582
Johan Hedbergaee9b212012-02-18 15:07:59 +02001583 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001584
1585unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001586 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001587 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001588 hci_dev_put(hdev);
1589 return err;
1590}
1591
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001592static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1593 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1594{
1595 struct pending_cmd *cmd;
1596 int err;
1597
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001598 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001599 sizeof(*cp));
1600 if (!cmd)
1601 return -ENOMEM;
1602
Johan Hedbergd8457692012-02-17 14:24:57 +02001603 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1604 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001605 if (err < 0)
1606 mgmt_pending_remove(cmd);
1607
1608 return err;
1609}
1610
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001611static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001612{
1613 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001614 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001615 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001616 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001617 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001618 int err;
1619
1620 BT_DBG("");
1621
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001622 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001623 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1624 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001625
Szymon Janc4e51eae2011-02-25 19:05:48 +01001626 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001627 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001628 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1629 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001630
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001631 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001632
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001633 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1635 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001636 goto failed;
1637 }
1638
Johan Hedbergd8457692012-02-17 14:24:57 +02001639 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001640 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001641 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1642 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001643 goto failed;
1644 }
1645
1646 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001647 struct mgmt_cp_pin_code_neg_reply ncp;
1648
1649 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001650
1651 BT_ERR("PIN code is not 16 bytes long");
1652
1653 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1654 if (err >= 0)
1655 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001656 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001657
1658 goto failed;
1659 }
1660
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001661 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1662 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001663 if (!cmd) {
1664 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001665 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001666 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001667
Johan Hedbergd8457692012-02-17 14:24:57 +02001668 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001669 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001670 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001671
1672 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1673 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001674 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001675
1676failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001677 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001678 hci_dev_put(hdev);
1679
1680 return err;
1681}
1682
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001683static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001684{
1685 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001686 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001687 int err;
1688
1689 BT_DBG("");
1690
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001691 if (len != sizeof(*cp))
1692 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001693 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001694
Szymon Janc4e51eae2011-02-25 19:05:48 +01001695 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001696 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001697 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001698 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001700 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001701
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001702 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001703 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001704 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001705 goto failed;
1706 }
1707
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001708 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001709
1710failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001711 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001712 hci_dev_put(hdev);
1713
1714 return err;
1715}
1716
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001717static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001718{
1719 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001720 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001721
1722 BT_DBG("");
1723
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001724 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001725 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1726 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001727
Szymon Janc4e51eae2011-02-25 19:05:48 +01001728 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001729 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001730 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1731 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001733 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001734
1735 hdev->io_capability = cp->io_capability;
1736
1737 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001738 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001740 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001741 hci_dev_put(hdev);
1742
Johan Hedbergaee9b212012-02-18 15:07:59 +02001743 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001744}
1745
Johan Hedberge9a416b2011-02-19 12:05:56 -03001746static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1747{
1748 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001749 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001750
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001751 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001752 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1753 continue;
1754
Johan Hedberge9a416b2011-02-19 12:05:56 -03001755 if (cmd->user_data != conn)
1756 continue;
1757
1758 return cmd;
1759 }
1760
1761 return NULL;
1762}
1763
1764static void pairing_complete(struct pending_cmd *cmd, u8 status)
1765{
1766 struct mgmt_rp_pair_device rp;
1767 struct hci_conn *conn = cmd->user_data;
1768
Johan Hedbergba4e5642011-11-11 00:07:34 +02001769 bacpy(&rp.addr.bdaddr, &conn->dst);
1770 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001771
Johan Hedbergaee9b212012-02-18 15:07:59 +02001772 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1773 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001774
1775 /* So we don't get further callbacks for this connection */
1776 conn->connect_cfm_cb = NULL;
1777 conn->security_cfm_cb = NULL;
1778 conn->disconn_cfm_cb = NULL;
1779
1780 hci_conn_put(conn);
1781
Johan Hedberga664b5b2011-02-19 12:06:02 -03001782 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001783}
1784
1785static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1786{
1787 struct pending_cmd *cmd;
1788
1789 BT_DBG("status %u", status);
1790
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001791 cmd = find_pairing(conn);
1792 if (!cmd)
1793 BT_DBG("Unable to find a pending command");
1794 else
Johan Hedberge2113262012-02-18 15:20:03 +02001795 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001796}
1797
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001798static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001799{
1800 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001801 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001802 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001803 struct pending_cmd *cmd;
1804 u8 sec_level, auth_type;
1805 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806 int err;
1807
1808 BT_DBG("");
1809
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001810 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001811 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1812 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001813
Szymon Janc4e51eae2011-02-25 19:05:48 +01001814 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001816 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1817 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001818
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001819 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001820
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001821 sec_level = BT_SECURITY_MEDIUM;
1822 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001823 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001824 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001825 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001826
Johan Hedbergba4e5642011-11-11 00:07:34 +02001827 if (cp->addr.type == MGMT_ADDR_BREDR)
1828 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001829 auth_type);
1830 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001831 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001832 auth_type);
1833
Johan Hedberg1425acb2011-11-11 00:07:35 +02001834 memset(&rp, 0, sizeof(rp));
1835 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1836 rp.addr.type = cp->addr.type;
1837
Ville Tervo30e76272011-02-22 16:10:53 -03001838 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001839 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1840 MGMT_STATUS_CONNECT_FAILED,
1841 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842 goto unlock;
1843 }
1844
1845 if (conn->connect_cfm_cb) {
1846 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001847 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1848 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849 goto unlock;
1850 }
1851
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001852 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001853 if (!cmd) {
1854 err = -ENOMEM;
1855 hci_conn_put(conn);
1856 goto unlock;
1857 }
1858
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001859 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001860 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001861 conn->connect_cfm_cb = pairing_complete_cb;
1862
Johan Hedberge9a416b2011-02-19 12:05:56 -03001863 conn->security_cfm_cb = pairing_complete_cb;
1864 conn->disconn_cfm_cb = pairing_complete_cb;
1865 conn->io_capability = cp->io_cap;
1866 cmd->user_data = conn;
1867
1868 if (conn->state == BT_CONNECTED &&
1869 hci_conn_security(conn, sec_level, auth_type))
1870 pairing_complete(cmd, 0);
1871
1872 err = 0;
1873
1874unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001875 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001876 hci_dev_put(hdev);
1877
1878 return err;
1879}
1880
Johan Hedberg28424702012-02-02 04:02:29 +02001881static int cancel_pair_device(struct sock *sk, u16 index,
1882 unsigned char *data, u16 len)
1883{
1884 struct mgmt_addr_info *addr = (void *) data;
1885 struct hci_dev *hdev;
1886 struct pending_cmd *cmd;
1887 struct hci_conn *conn;
1888 int err;
1889
1890 BT_DBG("");
1891
1892 if (len != sizeof(*addr))
1893 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1894 MGMT_STATUS_INVALID_PARAMS);
1895
1896 hdev = hci_dev_get(index);
1897 if (!hdev)
1898 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1899 MGMT_STATUS_INVALID_PARAMS);
1900
1901 hci_dev_lock(hdev);
1902
1903 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1904 if (!cmd) {
1905 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1906 MGMT_STATUS_INVALID_PARAMS);
1907 goto unlock;
1908 }
1909
1910 conn = cmd->user_data;
1911
1912 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1913 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1914 MGMT_STATUS_INVALID_PARAMS);
1915 goto unlock;
1916 }
1917
1918 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1919
Johan Hedbergaee9b212012-02-18 15:07:59 +02001920 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001921 sizeof(*addr));
1922unlock:
1923 hci_dev_unlock(hdev);
1924 hci_dev_put(hdev);
1925
1926 return err;
1927}
1928
Brian Gix0df4c182011-11-16 13:53:13 -08001929static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001930 u8 type, u16 mgmt_op, u16 hci_op,
1931 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001932{
Johan Hedberga5c29682011-02-19 12:05:57 -03001933 struct pending_cmd *cmd;
1934 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001935 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001936 int err;
1937
Szymon Janc4e51eae2011-02-25 19:05:48 +01001938 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001939 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001940 return cmd_status(sk, index, mgmt_op,
1941 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001942
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001943 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001944
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001945 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001946 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1947 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001948 }
1949
Johan Hedberg272d90d2012-02-09 15:26:12 +02001950 if (type == MGMT_ADDR_BREDR)
1951 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1952 else
Brian Gix47c15e22011-11-16 13:53:14 -08001953 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001954
Johan Hedberg272d90d2012-02-09 15:26:12 +02001955 if (!conn) {
1956 err = cmd_status(sk, index, mgmt_op,
1957 MGMT_STATUS_NOT_CONNECTED);
1958 goto done;
1959 }
1960
1961 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001962 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001963 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001964
Brian Gix5fe57d92011-12-21 16:12:13 -08001965 if (!err)
1966 err = cmd_status(sk, index, mgmt_op,
1967 MGMT_STATUS_SUCCESS);
1968 else
1969 err = cmd_status(sk, index, mgmt_op,
1970 MGMT_STATUS_FAILED);
1971
Brian Gix47c15e22011-11-16 13:53:14 -08001972 goto done;
1973 }
1974
Brian Gix0df4c182011-11-16 13:53:13 -08001975 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001976 if (!cmd) {
1977 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001978 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001979 }
1980
Brian Gix0df4c182011-11-16 13:53:13 -08001981 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001982 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1983 struct hci_cp_user_passkey_reply cp;
1984
1985 bacpy(&cp.bdaddr, bdaddr);
1986 cp.passkey = passkey;
1987 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1988 } else
1989 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1990
Johan Hedberga664b5b2011-02-19 12:06:02 -03001991 if (err < 0)
1992 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001993
Brian Gix0df4c182011-11-16 13:53:13 -08001994done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001996 hci_dev_put(hdev);
1997
1998 return err;
1999}
2000
Brian Gix0df4c182011-11-16 13:53:13 -08002001static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002003 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002004
2005 BT_DBG("");
2006
2007 if (len != sizeof(*cp))
2008 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2009 MGMT_STATUS_INVALID_PARAMS);
2010
Johan Hedberg272d90d2012-02-09 15:26:12 +02002011 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2012 MGMT_OP_USER_CONFIRM_REPLY,
2013 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002014}
2015
2016static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2017 u16 len)
2018{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002019 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002020
2021 BT_DBG("");
2022
2023 if (len != sizeof(*cp))
2024 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2025 MGMT_STATUS_INVALID_PARAMS);
2026
Johan Hedberg272d90d2012-02-09 15:26:12 +02002027 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2028 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2029 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002030}
2031
Brian Gix604086b2011-11-23 08:28:33 -08002032static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2033{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002034 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002035
2036 BT_DBG("");
2037
2038 if (len != sizeof(*cp))
2039 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2040 EINVAL);
2041
Johan Hedberg272d90d2012-02-09 15:26:12 +02002042 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2043 MGMT_OP_USER_PASSKEY_REPLY,
2044 HCI_OP_USER_PASSKEY_REPLY,
2045 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002046}
2047
2048static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2049 u16 len)
2050{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002051 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002052
2053 BT_DBG("");
2054
2055 if (len != sizeof(*cp))
2056 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2057 EINVAL);
2058
Johan Hedberg272d90d2012-02-09 15:26:12 +02002059 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2060 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2061 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002062}
2063
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002065 u16 len)
2066{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002067 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002068 struct hci_cp_write_local_name hci_cp;
2069 struct hci_dev *hdev;
2070 struct pending_cmd *cmd;
2071 int err;
2072
2073 BT_DBG("");
2074
2075 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002076 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2077 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002078
2079 hdev = hci_dev_get(index);
2080 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002081 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2082 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002083
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002084 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002085
Johan Hedbergb5235a62012-02-21 14:32:24 +02002086 if (!hdev_is_powered(hdev)) {
2087 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2088 MGMT_STATUS_NOT_POWERED);
2089 goto failed;
2090 }
2091
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002092 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2093 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002094 if (!cmd) {
2095 err = -ENOMEM;
2096 goto failed;
2097 }
2098
2099 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2100 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2101 &hci_cp);
2102 if (err < 0)
2103 mgmt_pending_remove(cmd);
2104
2105failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002106 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002107 hci_dev_put(hdev);
2108
2109 return err;
2110}
2111
Szymon Jancc35938b2011-03-22 13:12:21 +01002112static int read_local_oob_data(struct sock *sk, u16 index)
2113{
2114 struct hci_dev *hdev;
2115 struct pending_cmd *cmd;
2116 int err;
2117
2118 BT_DBG("hci%u", index);
2119
2120 hdev = hci_dev_get(index);
2121 if (!hdev)
2122 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002123 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002125 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002126
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002127 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002128 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002129 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002130 goto unlock;
2131 }
2132
2133 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2134 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002135 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002136 goto unlock;
2137 }
2138
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002139 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002140 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2141 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002142 goto unlock;
2143 }
2144
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002145 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002146 if (!cmd) {
2147 err = -ENOMEM;
2148 goto unlock;
2149 }
2150
2151 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2152 if (err < 0)
2153 mgmt_pending_remove(cmd);
2154
2155unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002157 hci_dev_put(hdev);
2158
2159 return err;
2160}
2161
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002162static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2163 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002164{
2165 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002166 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002167 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002168 int err;
2169
2170 BT_DBG("hci%u ", index);
2171
2172 if (len != sizeof(*cp))
2173 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002174 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002175
2176 hdev = hci_dev_get(index);
2177 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002178 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2179 MGMT_STATUS_INVALID_PARAMS,
2180 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002181
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002182 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002183
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002184 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002185 cp->randomizer);
2186 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002187 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002188 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002189 status = 0;
2190
2191 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2192 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002195 hci_dev_put(hdev);
2196
2197 return err;
2198}
2199
2200static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002202{
2203 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002204 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002205 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002206 int err;
2207
2208 BT_DBG("hci%u ", index);
2209
2210 if (len != sizeof(*cp))
2211 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002212 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002213
2214 hdev = hci_dev_get(index);
2215 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002216 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2217 MGMT_STATUS_INVALID_PARAMS,
2218 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002219
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002220 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002221
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002222 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002223 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002225 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002226 status = 0;
2227
2228 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2229 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002230
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002231 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002232 hci_dev_put(hdev);
2233
2234 return err;
2235}
2236
Andre Guedes5e0452c2012-02-17 20:39:38 -03002237static int discovery(struct hci_dev *hdev)
2238{
2239 int err;
2240
2241 if (lmp_host_le_capable(hdev)) {
2242 if (lmp_bredr_capable(hdev)) {
2243 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2244 LE_SCAN_INT, LE_SCAN_WIN,
2245 LE_SCAN_TIMEOUT_BREDR_LE);
2246 } else {
2247 hdev->discovery.type = DISCOV_TYPE_LE;
2248 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2249 LE_SCAN_INT, LE_SCAN_WIN,
2250 LE_SCAN_TIMEOUT_LE_ONLY);
2251 }
2252 } else {
2253 hdev->discovery.type = DISCOV_TYPE_BREDR;
2254 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2255 }
2256
2257 return err;
2258}
2259
2260int mgmt_interleaved_discovery(struct hci_dev *hdev)
2261{
2262 int err;
2263
2264 BT_DBG("%s", hdev->name);
2265
2266 hci_dev_lock(hdev);
2267
2268 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2269 if (err < 0)
2270 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2271
2272 hci_dev_unlock(hdev);
2273
2274 return err;
2275}
2276
Johan Hedberg450dfda2011-11-12 11:58:22 +02002277static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002278 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002279{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002280 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002281 struct pending_cmd *cmd;
2282 struct hci_dev *hdev;
2283 int err;
2284
2285 BT_DBG("hci%u", index);
2286
Johan Hedberg450dfda2011-11-12 11:58:22 +02002287 if (len != sizeof(*cp))
2288 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2289 MGMT_STATUS_INVALID_PARAMS);
2290
Johan Hedberg14a53662011-04-27 10:29:56 -04002291 hdev = hci_dev_get(index);
2292 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002293 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2294 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002295
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002296 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002297
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002298 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002299 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2300 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002301 goto failed;
2302 }
2303
Johan Hedbergff9ef572012-01-04 14:23:45 +02002304 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2305 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2306 MGMT_STATUS_BUSY);
2307 goto failed;
2308 }
2309
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002310 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002311 if (!cmd) {
2312 err = -ENOMEM;
2313 goto failed;
2314 }
2315
Andre Guedes4aab14e2012-02-17 20:39:36 -03002316 hdev->discovery.type = cp->type;
2317
2318 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002319 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002320 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002321 break;
2322
2323 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002324 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2325 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002326 break;
2327
Andre Guedes5e0452c2012-02-17 20:39:38 -03002328 case DISCOV_TYPE_INTERLEAVED:
2329 err = discovery(hdev);
2330 break;
2331
Andre Guedesf39799f2012-02-17 20:39:35 -03002332 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002333 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002334 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002335
Johan Hedberg14a53662011-04-27 10:29:56 -04002336 if (err < 0)
2337 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002338 else
2339 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002340
2341failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002342 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002343 hci_dev_put(hdev);
2344
2345 return err;
2346}
2347
Johan Hedbergd9306502012-02-20 23:25:18 +02002348static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002349{
Johan Hedbergd9306502012-02-20 23:25:18 +02002350 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002351 struct hci_dev *hdev;
2352 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002353 struct hci_cp_remote_name_req_cancel cp;
2354 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002355 int err;
2356
2357 BT_DBG("hci%u", index);
2358
Johan Hedbergd9306502012-02-20 23:25:18 +02002359 if (len != sizeof(*mgmt_cp))
2360 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2361 MGMT_STATUS_INVALID_PARAMS);
2362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 hdev = hci_dev_get(index);
2364 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002365 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2366 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002368 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002369
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002370 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002371 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2372 MGMT_STATUS_REJECTED,
2373 &mgmt_cp->type, sizeof(mgmt_cp->type));
2374 goto unlock;
2375 }
2376
2377 if (hdev->discovery.type != mgmt_cp->type) {
2378 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2379 MGMT_STATUS_INVALID_PARAMS,
2380 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002381 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002382 }
2383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002384 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385 if (!cmd) {
2386 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002387 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 }
2389
Andre Guedes343f9352012-02-17 20:39:37 -03002390 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002391 err = hci_cancel_inquiry(hdev);
2392 if (err < 0)
2393 mgmt_pending_remove(cmd);
2394 else
2395 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2396 goto unlock;
2397 }
2398
2399 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2400 if (!e) {
2401 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002402 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002403 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002404 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2405 goto unlock;
2406 }
2407
2408 bacpy(&cp.bdaddr, &e->data.bdaddr);
2409 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2410 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002411 if (err < 0)
2412 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002413 else
2414 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002415
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002416unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002417 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002418 hci_dev_put(hdev);
2419
2420 return err;
2421}
2422
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002423static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002424{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002425 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002426 struct inquiry_entry *e;
2427 struct hci_dev *hdev;
2428 int err;
2429
2430 BT_DBG("hci%u", index);
2431
2432 if (len != sizeof(*cp))
2433 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2434 MGMT_STATUS_INVALID_PARAMS);
2435
2436 hdev = hci_dev_get(index);
2437 if (!hdev)
2438 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2439 MGMT_STATUS_INVALID_PARAMS);
2440
2441 hci_dev_lock(hdev);
2442
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002443 if (!hci_discovery_active(hdev)) {
2444 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2445 MGMT_STATUS_FAILED);
2446 goto failed;
2447 }
2448
Johan Hedberga198e7b2012-02-17 14:27:06 +02002449 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002450 if (!e) {
2451 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2452 MGMT_STATUS_INVALID_PARAMS);
2453 goto failed;
2454 }
2455
2456 if (cp->name_known) {
2457 e->name_state = NAME_KNOWN;
2458 list_del(&e->list);
2459 } else {
2460 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002461 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462 }
2463
2464 err = 0;
2465
2466failed:
2467 hci_dev_unlock(hdev);
2468
2469 return err;
2470}
2471
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002472static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002473{
2474 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002475 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002476 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002477 int err;
2478
2479 BT_DBG("hci%u", index);
2480
Antti Julku7fbec222011-06-15 12:01:15 +03002481 if (len != sizeof(*cp))
2482 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002483 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002484
2485 hdev = hci_dev_get(index);
2486 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002487 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2488 MGMT_STATUS_INVALID_PARAMS,
2489 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002490
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002492
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002493 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002494 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002495 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002496 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002497 status = 0;
2498
2499 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2500 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002502 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002503 hci_dev_put(hdev);
2504
2505 return err;
2506}
2507
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002509{
2510 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002511 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002512 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002513 int err;
2514
2515 BT_DBG("hci%u", index);
2516
Antti Julku7fbec222011-06-15 12:01:15 +03002517 if (len != sizeof(*cp))
2518 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002519 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002520
2521 hdev = hci_dev_get(index);
2522 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002523 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2524 MGMT_STATUS_INVALID_PARAMS,
2525 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002526
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002528
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002529 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002530 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002531 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002532 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002533 status = 0;
2534
2535 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2536 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002539 hci_dev_put(hdev);
2540
2541 return err;
2542}
2543
Antti Julkuf6422ec2011-06-22 13:11:56 +03002544static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002545 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002546{
2547 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002548 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002549 struct hci_cp_write_page_scan_activity acp;
2550 u8 type;
2551 int err;
2552
2553 BT_DBG("hci%u", index);
2554
2555 if (len != sizeof(*cp))
2556 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002557 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002558
2559 hdev = hci_dev_get(index);
2560 if (!hdev)
2561 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002562 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002563 if (!hdev_is_powered(hdev))
2564 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2565 MGMT_STATUS_NOT_POWERED);
2566
2567 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2568 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2569 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002570
2571 hci_dev_lock(hdev);
2572
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002573 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002574 type = PAGE_SCAN_TYPE_INTERLACED;
2575 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2576 } else {
2577 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2578 acp.interval = 0x0800; /* default 1.28 sec page scan */
2579 }
2580
2581 acp.window = 0x0012; /* default 11.25 msec page scan window */
2582
2583 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2584 sizeof(acp), &acp);
2585 if (err < 0) {
2586 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002587 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002588 goto done;
2589 }
2590
2591 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2592 if (err < 0) {
2593 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002594 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002595 goto done;
2596 }
2597
Johan Hedbergaee9b212012-02-18 15:07:59 +02002598 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2599 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002600done:
2601 hci_dev_unlock(hdev);
2602 hci_dev_put(hdev);
2603
2604 return err;
2605}
2606
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002607static int load_long_term_keys(struct sock *sk, u16 index,
2608 void *cp_data, u16 len)
2609{
2610 struct hci_dev *hdev;
2611 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2612 u16 key_count, expected_len;
2613 int i;
2614
2615 if (len < sizeof(*cp))
2616 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2617 EINVAL);
2618
2619 key_count = get_unaligned_le16(&cp->key_count);
2620
2621 expected_len = sizeof(*cp) + key_count *
2622 sizeof(struct mgmt_ltk_info);
2623 if (expected_len != len) {
2624 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2625 len, expected_len);
2626 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2627 EINVAL);
2628 }
2629
2630 hdev = hci_dev_get(index);
2631 if (!hdev)
2632 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2633 ENODEV);
2634
2635 BT_DBG("hci%u key_count %u", index, key_count);
2636
2637 hci_dev_lock(hdev);
2638
2639 hci_smp_ltks_clear(hdev);
2640
2641 for (i = 0; i < key_count; i++) {
2642 struct mgmt_ltk_info *key = &cp->keys[i];
2643 u8 type;
2644
2645 if (key->master)
2646 type = HCI_SMP_LTK;
2647 else
2648 type = HCI_SMP_LTK_SLAVE;
2649
2650 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2651 type, 0, key->authenticated, key->val,
2652 key->enc_size, key->ediv, key->rand);
2653 }
2654
2655 hci_dev_unlock(hdev);
2656 hci_dev_put(hdev);
2657
2658 return 0;
2659}
2660
Johan Hedberg03811012010-12-08 00:21:06 +02002661int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2662{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002663 void *buf;
2664 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002665 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002666 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002667 int err;
2668
2669 BT_DBG("got %zu bytes", msglen);
2670
2671 if (msglen < sizeof(*hdr))
2672 return -EINVAL;
2673
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002674 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002675 if (!buf)
2676 return -ENOMEM;
2677
2678 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2679 err = -EFAULT;
2680 goto done;
2681 }
2682
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002683 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002684 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002685 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002686 len = get_unaligned_le16(&hdr->len);
2687
2688 if (len != msglen - sizeof(*hdr)) {
2689 err = -EINVAL;
2690 goto done;
2691 }
2692
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002693 cp = buf + sizeof(*hdr);
2694
Johan Hedberg03811012010-12-08 00:21:06 +02002695 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002696 case MGMT_OP_READ_VERSION:
2697 err = read_version(sk);
2698 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002699 case MGMT_OP_READ_COMMANDS:
2700 err = read_commands(sk);
2701 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002702 case MGMT_OP_READ_INDEX_LIST:
2703 err = read_index_list(sk);
2704 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002705 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002706 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002707 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002708 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002710 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002711 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002713 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002714 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002715 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002716 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002717 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002718 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002719 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002720 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002721 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002722 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002723 case MGMT_OP_SET_LINK_SECURITY:
2724 err = set_link_security(sk, index, cp, len);
2725 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002726 case MGMT_OP_SET_SSP:
2727 err = set_ssp(sk, index, cp, len);
2728 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002729 case MGMT_OP_SET_HS:
2730 err = set_hs(sk, index, cp, len);
2731 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002732 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002734 break;
2735 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002736 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002737 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002738 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002740 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002741 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002743 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002744 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002746 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002747 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002748 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002749 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002750 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002752 break;
2753 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002754 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002755 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002756 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002757 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002758 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002760 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002762 case MGMT_OP_CANCEL_PAIR_DEVICE:
2763 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2764 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002765 case MGMT_OP_UNPAIR_DEVICE:
2766 err = unpair_device(sk, index, cp, len);
2767 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002768 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002769 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002770 break;
2771 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002772 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002773 break;
Brian Gix604086b2011-11-23 08:28:33 -08002774 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002775 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002776 break;
2777 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002779 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002780 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002781 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002782 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002783 case MGMT_OP_READ_LOCAL_OOB_DATA:
2784 err = read_local_oob_data(sk, index);
2785 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002786 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002787 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002788 break;
2789 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002791 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002792 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002793 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002794 break;
2795 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002796 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002797 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002798 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002799 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002800 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002801 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002802 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002803 break;
2804 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002806 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002807 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2808 err = load_long_term_keys(sk, index, cp, len);
2809 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002810 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002811 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002812 err = cmd_status(sk, index, opcode,
2813 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002814 break;
2815 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002816
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002817 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002818 goto done;
2819
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002820 err = msglen;
2821
2822done:
2823 kfree(buf);
2824 return err;
2825}
2826
Johan Hedbergb24752f2011-11-03 14:40:33 +02002827static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2828{
2829 u8 *status = data;
2830
2831 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2832 mgmt_pending_remove(cmd);
2833}
2834
Johan Hedberg744cf192011-11-08 20:40:14 +02002835int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002836{
Johan Hedberg744cf192011-11-08 20:40:14 +02002837 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002838}
2839
Johan Hedberg744cf192011-11-08 20:40:14 +02002840int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002841{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002842 u8 status = ENODEV;
2843
Johan Hedberg744cf192011-11-08 20:40:14 +02002844 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002845
Johan Hedberg744cf192011-11-08 20:40:14 +02002846 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002847}
2848
2849struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002850 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002851 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002852};
2853
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002854static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002855{
Johan Hedberg03811012010-12-08 00:21:06 +02002856 struct cmd_lookup *match = data;
2857
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002858 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002859
2860 list_del(&cmd->list);
2861
2862 if (match->sk == NULL) {
2863 match->sk = cmd->sk;
2864 sock_hold(match->sk);
2865 }
2866
2867 mgmt_pending_free(cmd);
2868}
2869
Johan Hedberg744cf192011-11-08 20:40:14 +02002870int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002871{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002872 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002873 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002874 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002875
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002876 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002877
Johan Hedbergb24752f2011-11-03 14:40:33 +02002878 if (!powered) {
2879 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002880 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002881 }
2882
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002883 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002884
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002885 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002886 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002887
2888 if (match.sk)
2889 sock_put(match.sk);
2890
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002891 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002892}
2893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002895{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002896 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002897 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002898 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002899
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002900 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002901
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002902 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002903
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002904 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002905 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002906 if (match.sk)
2907 sock_put(match.sk);
2908
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002909 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002910}
2911
Johan Hedberg744cf192011-11-08 20:40:14 +02002912int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002913{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002914 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002915 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002916 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002917
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002918 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2919 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002920
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002921 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002922
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002923 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002924
2925 if (match.sk)
2926 sock_put(match.sk);
2927
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002928 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002929}
2930
Johan Hedberg744cf192011-11-08 20:40:14 +02002931int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002932{
Johan Hedbergca69b792011-11-11 18:10:00 +02002933 u8 mgmt_err = mgmt_status(status);
2934
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002935 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002936 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002937 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002938
2939 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002940 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002941 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002942
2943 return 0;
2944}
2945
Johan Hedberg744cf192011-11-08 20:40:14 +02002946int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2947 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002948{
Johan Hedberg86742e12011-11-07 23:13:38 +02002949 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002950
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002951 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002952
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002953 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002954 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2955 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002956 ev.key.type = key->type;
2957 memcpy(ev.key.val, key->val, 16);
2958 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002959
Johan Hedberg744cf192011-11-08 20:40:14 +02002960 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002961}
Johan Hedbergf7520542011-01-20 12:34:39 +02002962
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002963int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2964{
2965 struct mgmt_ev_new_long_term_key ev;
2966
2967 memset(&ev, 0, sizeof(ev));
2968
2969 ev.store_hint = persistent;
2970 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2971 ev.key.addr.type = key->bdaddr_type;
2972 ev.key.authenticated = key->authenticated;
2973 ev.key.enc_size = key->enc_size;
2974 ev.key.ediv = key->ediv;
2975
2976 if (key->type == HCI_SMP_LTK)
2977 ev.key.master = 1;
2978
2979 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2980 memcpy(ev.key.val, key->val, sizeof(key->val));
2981
2982 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2983 &ev, sizeof(ev), NULL);
2984}
2985
Johan Hedbergafc747a2012-01-15 18:11:07 +02002986int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002987 u8 addr_type, u8 *name, u8 name_len,
2988 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002989{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002990 char buf[512];
2991 struct mgmt_ev_device_connected *ev = (void *) buf;
2992 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002993
Johan Hedbergb644ba32012-01-17 21:48:47 +02002994 bacpy(&ev->addr.bdaddr, bdaddr);
2995 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002996
Johan Hedbergb644ba32012-01-17 21:48:47 +02002997 if (name_len > 0)
2998 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2999 name, name_len);
3000
3001 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3002 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3003 EIR_CLASS_OF_DEV, dev_class, 3);
3004
3005 put_unaligned_le16(eir_len, &ev->eir_len);
3006
3007 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3008 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003009}
3010
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3012{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003013 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003015 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016
Johan Hedberg88c3df12012-02-09 14:27:38 +02003017 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3018 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003019
Johan Hedbergaee9b212012-02-18 15:07:59 +02003020 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3021 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003022
3023 *sk = cmd->sk;
3024 sock_hold(*sk);
3025
Johan Hedberga664b5b2011-02-19 12:06:02 -03003026 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003027}
3028
Johan Hedberg124f6e32012-02-09 13:50:12 +02003029static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003030{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003031 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003032 struct mgmt_cp_unpair_device *cp = cmd->param;
3033 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003034
3035 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003036 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3037 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003038
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003039 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3040
Johan Hedbergaee9b212012-02-18 15:07:59 +02003041 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003042
3043 mgmt_pending_remove(cmd);
3044}
3045
Johan Hedbergafc747a2012-01-15 18:11:07 +02003046int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3047 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003048{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003049 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050 struct sock *sk = NULL;
3051 int err;
3052
Johan Hedberg744cf192011-11-08 20:40:14 +02003053 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003054
Johan Hedbergf7520542011-01-20 12:34:39 +02003055 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003056 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003057
Johan Hedbergafc747a2012-01-15 18:11:07 +02003058 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3059 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003060
3061 if (sk)
3062 sock_put(sk);
3063
Johan Hedberg124f6e32012-02-09 13:50:12 +02003064 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003065 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003066
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 return err;
3068}
3069
Johan Hedberg88c3df12012-02-09 14:27:38 +02003070int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3071 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003072{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003073 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003074 struct pending_cmd *cmd;
3075 int err;
3076
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003077 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003078 if (!cmd)
3079 return -ENOENT;
3080
Johan Hedberg88c3df12012-02-09 14:27:38 +02003081 bacpy(&rp.addr.bdaddr, bdaddr);
3082 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003083
Johan Hedberg88c3df12012-02-09 14:27:38 +02003084 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003085 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003086
Johan Hedberga664b5b2011-02-19 12:06:02 -03003087 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003089 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3090 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003091 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003092}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003093
Johan Hedberg48264f02011-11-09 13:58:58 +02003094int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3095 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003096{
3097 struct mgmt_ev_connect_failed ev;
3098
Johan Hedberg4c659c32011-11-07 23:13:39 +02003099 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003100 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003101 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003102
Johan Hedberg744cf192011-11-08 20:40:14 +02003103 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003104}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003105
Johan Hedberg744cf192011-11-08 20:40:14 +02003106int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003107{
3108 struct mgmt_ev_pin_code_request ev;
3109
Johan Hedbergd8457692012-02-17 14:24:57 +02003110 bacpy(&ev.addr.bdaddr, bdaddr);
3111 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003112 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003113
Johan Hedberg744cf192011-11-08 20:40:14 +02003114 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003115 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003116}
3117
Johan Hedberg744cf192011-11-08 20:40:14 +02003118int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3119 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003120{
3121 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003122 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123 int err;
3124
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003125 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003126 if (!cmd)
3127 return -ENOENT;
3128
Johan Hedbergd8457692012-02-17 14:24:57 +02003129 bacpy(&rp.addr.bdaddr, bdaddr);
3130 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003131
Johan Hedbergaee9b212012-02-18 15:07:59 +02003132 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3133 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003134
Johan Hedberga664b5b2011-02-19 12:06:02 -03003135 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136
3137 return err;
3138}
3139
Johan Hedberg744cf192011-11-08 20:40:14 +02003140int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3141 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003142{
3143 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003144 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003145 int err;
3146
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003147 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003148 if (!cmd)
3149 return -ENOENT;
3150
Johan Hedbergd8457692012-02-17 14:24:57 +02003151 bacpy(&rp.addr.bdaddr, bdaddr);
3152 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003153
Johan Hedbergaee9b212012-02-18 15:07:59 +02003154 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3155 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003156
Johan Hedberga664b5b2011-02-19 12:06:02 -03003157 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158
3159 return err;
3160}
Johan Hedberga5c29682011-02-19 12:05:57 -03003161
Johan Hedberg744cf192011-11-08 20:40:14 +02003162int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003163 u8 link_type, u8 addr_type, __le32 value,
3164 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003165{
3166 struct mgmt_ev_user_confirm_request ev;
3167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003169
Johan Hedberg272d90d2012-02-09 15:26:12 +02003170 bacpy(&ev.addr.bdaddr, bdaddr);
3171 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003172 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003173 put_unaligned_le32(value, &ev.value);
3174
Johan Hedberg744cf192011-11-08 20:40:14 +02003175 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003176 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003177}
3178
Johan Hedberg272d90d2012-02-09 15:26:12 +02003179int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3180 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003181{
3182 struct mgmt_ev_user_passkey_request ev;
3183
3184 BT_DBG("%s", hdev->name);
3185
Johan Hedberg272d90d2012-02-09 15:26:12 +02003186 bacpy(&ev.addr.bdaddr, bdaddr);
3187 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003188
3189 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3190 NULL);
3191}
3192
Brian Gix0df4c182011-11-16 13:53:13 -08003193static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003194 u8 link_type, u8 addr_type, u8 status,
3195 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003196{
3197 struct pending_cmd *cmd;
3198 struct mgmt_rp_user_confirm_reply rp;
3199 int err;
3200
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003201 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003202 if (!cmd)
3203 return -ENOENT;
3204
Johan Hedberg272d90d2012-02-09 15:26:12 +02003205 bacpy(&rp.addr.bdaddr, bdaddr);
3206 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003207 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3208 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003209
Johan Hedberga664b5b2011-02-19 12:06:02 -03003210 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003211
3212 return err;
3213}
3214
Johan Hedberg744cf192011-11-08 20:40:14 +02003215int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003216 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003217{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003218 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3219 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003220}
3221
Johan Hedberg272d90d2012-02-09 15:26:12 +02003222int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3223 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003224{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003225 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3226 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003227}
Johan Hedberg2a611692011-02-19 12:06:00 -03003228
Brian Gix604086b2011-11-23 08:28:33 -08003229int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003230 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003231{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003232 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3233 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003234}
3235
Johan Hedberg272d90d2012-02-09 15:26:12 +02003236int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3237 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003238{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003239 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3240 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003241}
3242
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003243int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3244 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003245{
3246 struct mgmt_ev_auth_failed ev;
3247
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003248 bacpy(&ev.addr.bdaddr, bdaddr);
3249 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003250 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003251
Johan Hedberg744cf192011-11-08 20:40:14 +02003252 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003253}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003254
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003255int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3256{
3257 struct cmd_lookup match = { NULL, hdev };
3258 __le32 ev;
3259 int err;
3260
3261 if (status) {
3262 u8 mgmt_err = mgmt_status(status);
3263 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3264 cmd_status_rsp, &mgmt_err);
3265 return 0;
3266 }
3267
3268 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3269 &match);
3270
3271 ev = cpu_to_le32(get_current_settings(hdev));
3272 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3273
3274 if (match.sk)
3275 sock_put(match.sk);
3276
3277 return err;
3278}
3279
Johan Hedbergcacaf522012-02-21 00:52:42 +02003280static int clear_eir(struct hci_dev *hdev)
3281{
3282 struct hci_cp_write_eir cp;
3283
3284 if (!(hdev->features[6] & LMP_EXT_INQ))
3285 return 0;
3286
3287 memset(&cp, 0, sizeof(cp));
3288
3289 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3290}
3291
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003292int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3293{
3294 struct cmd_lookup match = { NULL, hdev };
3295 __le32 ev;
3296 int err;
3297
3298 if (status) {
3299 u8 mgmt_err = mgmt_status(status);
3300 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3301 cmd_status_rsp, &mgmt_err);
3302 return 0;
3303 }
3304
3305 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3306
3307 ev = cpu_to_le32(get_current_settings(hdev));
3308 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3309
Johan Hedbergcacaf522012-02-21 00:52:42 +02003310 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003311 sock_put(match.sk);
3312
Johan Hedbergcacaf522012-02-21 00:52:42 +02003313 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3314 update_eir(hdev);
3315 else
3316 clear_eir(hdev);
3317 }
3318
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003319 return err;
3320}
3321
Johan Hedberg744cf192011-11-08 20:40:14 +02003322int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003323{
3324 struct pending_cmd *cmd;
3325 struct mgmt_cp_set_local_name ev;
3326 int err;
3327
3328 memset(&ev, 0, sizeof(ev));
3329 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003331 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003332 if (!cmd)
3333 goto send_event;
3334
3335 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003336 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003337 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003338 goto failed;
3339 }
3340
Johan Hedberg744cf192011-11-08 20:40:14 +02003341 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003342
Johan Hedbergaee9b212012-02-18 15:07:59 +02003343 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003344 sizeof(ev));
3345 if (err < 0)
3346 goto failed;
3347
3348send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003349 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003350 cmd ? cmd->sk : NULL);
3351
3352failed:
3353 if (cmd)
3354 mgmt_pending_remove(cmd);
3355 return err;
3356}
Szymon Jancc35938b2011-03-22 13:12:21 +01003357
Johan Hedberg744cf192011-11-08 20:40:14 +02003358int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3359 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003360{
3361 struct pending_cmd *cmd;
3362 int err;
3363
Johan Hedberg744cf192011-11-08 20:40:14 +02003364 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003365
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003366 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003367 if (!cmd)
3368 return -ENOENT;
3369
3370 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003371 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003372 MGMT_OP_READ_LOCAL_OOB_DATA,
3373 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003374 } else {
3375 struct mgmt_rp_read_local_oob_data rp;
3376
3377 memcpy(rp.hash, hash, sizeof(rp.hash));
3378 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3379
Johan Hedberg744cf192011-11-08 20:40:14 +02003380 err = cmd_complete(cmd->sk, hdev->id,
3381 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003382 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003383 }
3384
3385 mgmt_pending_remove(cmd);
3386
3387 return err;
3388}
Johan Hedberge17acd42011-03-30 23:57:16 +03003389
Johan Hedberg48264f02011-11-09 13:58:58 +02003390int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003391 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003392 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003393{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003394 char buf[512];
3395 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003396 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003397
Johan Hedberg1dc06092012-01-15 21:01:23 +02003398 /* Leave 5 bytes for a potential CoD field */
3399 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003400 return -EINVAL;
3401
Johan Hedberg1dc06092012-01-15 21:01:23 +02003402 memset(buf, 0, sizeof(buf));
3403
Johan Hedberge319d2e2012-01-15 19:51:59 +02003404 bacpy(&ev->addr.bdaddr, bdaddr);
3405 ev->addr.type = link_to_mgmt(link_type, addr_type);
3406 ev->rssi = rssi;
3407 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003408
Johan Hedberg1dc06092012-01-15 21:01:23 +02003409 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003410 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003411
Johan Hedberg1dc06092012-01-15 21:01:23 +02003412 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3413 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3414 dev_class, 3);
3415
3416 put_unaligned_le16(eir_len, &ev->eir_len);
3417
3418 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003419
Johan Hedberge319d2e2012-01-15 19:51:59 +02003420 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003421}
Johan Hedberga88a9652011-03-30 13:18:12 +03003422
Johan Hedbergb644ba32012-01-17 21:48:47 +02003423int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3424 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003425{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003426 struct mgmt_ev_device_found *ev;
3427 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3428 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003429
Johan Hedbergb644ba32012-01-17 21:48:47 +02003430 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003431
Johan Hedbergb644ba32012-01-17 21:48:47 +02003432 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003433
Johan Hedbergb644ba32012-01-17 21:48:47 +02003434 bacpy(&ev->addr.bdaddr, bdaddr);
3435 ev->addr.type = link_to_mgmt(link_type, addr_type);
3436 ev->rssi = rssi;
3437
3438 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3439 name_len);
3440
3441 put_unaligned_le16(eir_len, &ev->eir_len);
3442
Johan Hedberg053c7e02012-02-04 00:06:00 +02003443 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3444 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003445}
Johan Hedberg314b2382011-04-27 10:29:57 -04003446
Andre Guedes7a135102011-11-09 17:14:25 -03003447int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003448{
3449 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003450 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003451 int err;
3452
Andre Guedes203159d2012-02-13 15:41:01 -03003453 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3454
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003455 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003456 if (!cmd)
3457 return -ENOENT;
3458
Johan Hedbergf808e162012-02-19 12:52:07 +02003459 type = hdev->discovery.type;
3460
3461 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3462 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003463 mgmt_pending_remove(cmd);
3464
3465 return err;
3466}
3467
Andre Guedese6d465c2011-11-09 17:14:26 -03003468int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3469{
3470 struct pending_cmd *cmd;
3471 int err;
3472
3473 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3474 if (!cmd)
3475 return -ENOENT;
3476
Johan Hedbergd9306502012-02-20 23:25:18 +02003477 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3478 &hdev->discovery.type,
3479 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003480 mgmt_pending_remove(cmd);
3481
3482 return err;
3483}
Johan Hedberg314b2382011-04-27 10:29:57 -04003484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003486{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003487 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003488 struct pending_cmd *cmd;
3489
Andre Guedes343fb142011-11-22 17:14:19 -03003490 BT_DBG("%s discovering %u", hdev->name, discovering);
3491
Johan Hedberg164a6e72011-11-01 17:06:44 +02003492 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003493 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003494 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003495 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003496
3497 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003498 u8 type = hdev->discovery.type;
3499
Johan Hedbergd9306502012-02-20 23:25:18 +02003500 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003501 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003502 mgmt_pending_remove(cmd);
3503 }
3504
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003505 memset(&ev, 0, sizeof(ev));
3506 ev.type = hdev->discovery.type;
3507 ev.discovering = discovering;
3508
3509 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003510}
Antti Julku5e762442011-08-25 16:48:02 +03003511
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003512int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003513{
3514 struct pending_cmd *cmd;
3515 struct mgmt_ev_device_blocked ev;
3516
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003517 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003518
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003519 bacpy(&ev.addr.bdaddr, bdaddr);
3520 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003521
Johan Hedberg744cf192011-11-08 20:40:14 +02003522 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3523 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003524}
3525
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003526int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003527{
3528 struct pending_cmd *cmd;
3529 struct mgmt_ev_device_unblocked ev;
3530
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003531 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003532
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003533 bacpy(&ev.addr.bdaddr, bdaddr);
3534 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003535
Johan Hedberg744cf192011-11-08 20:40:14 +02003536 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3537 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003538}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003539
3540module_param(enable_hs, bool, 0644);
3541MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3542
3543module_param(enable_le, bool, 0644);
3544MODULE_PARM_DESC(enable_le, "Enable Low Energy support");