blob: 9071886df19450b356a4dc7c91152db2461f4e8d [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
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedberg87510972016-07-13 10:57:18 +030041#define MGMT_REVISION 13
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,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 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,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200107};
108
109static const u16 mgmt_events[] = {
110 MGMT_EV_CONTROLLER_ERROR,
111 MGMT_EV_INDEX_ADDED,
112 MGMT_EV_INDEX_REMOVED,
113 MGMT_EV_NEW_SETTINGS,
114 MGMT_EV_CLASS_OF_DEV_CHANGED,
115 MGMT_EV_LOCAL_NAME_CHANGED,
116 MGMT_EV_NEW_LINK_KEY,
117 MGMT_EV_NEW_LONG_TERM_KEY,
118 MGMT_EV_DEVICE_CONNECTED,
119 MGMT_EV_DEVICE_DISCONNECTED,
120 MGMT_EV_CONNECT_FAILED,
121 MGMT_EV_PIN_CODE_REQUEST,
122 MGMT_EV_USER_CONFIRM_REQUEST,
123 MGMT_EV_USER_PASSKEY_REQUEST,
124 MGMT_EV_AUTH_FAILED,
125 MGMT_EV_DEVICE_FOUND,
126 MGMT_EV_DISCOVERING,
127 MGMT_EV_DEVICE_BLOCKED,
128 MGMT_EV_DEVICE_UNBLOCKED,
129 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300130 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800131 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700132 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200133 MGMT_EV_DEVICE_ADDED,
134 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300135 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200136 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200137 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200138 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700139 MGMT_EV_EXT_INDEX_ADDED,
140 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700141 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700142 MGMT_EV_ADVERTISING_ADDED,
143 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200144};
145
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700146static const u16 mgmt_untrusted_commands[] = {
147 MGMT_OP_READ_INDEX_LIST,
148 MGMT_OP_READ_INFO,
149 MGMT_OP_READ_UNCONF_INDEX_LIST,
150 MGMT_OP_READ_CONFIG_INFO,
151 MGMT_OP_READ_EXT_INDEX_LIST,
152};
153
154static const u16 mgmt_untrusted_events[] = {
155 MGMT_EV_INDEX_ADDED,
156 MGMT_EV_INDEX_REMOVED,
157 MGMT_EV_NEW_SETTINGS,
158 MGMT_EV_CLASS_OF_DEV_CHANGED,
159 MGMT_EV_LOCAL_NAME_CHANGED,
160 MGMT_EV_UNCONF_INDEX_ADDED,
161 MGMT_EV_UNCONF_INDEX_REMOVED,
162 MGMT_EV_NEW_CONFIG_OPTIONS,
163 MGMT_EV_EXT_INDEX_ADDED,
164 MGMT_EV_EXT_INDEX_REMOVED,
165};
166
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800167#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200168
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200169#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
170 "\x00\x00\x00\x00\x00\x00\x00\x00"
171
Johan Hedbergca69b792011-11-11 18:10:00 +0200172/* HCI to MGMT error code conversion table */
173static u8 mgmt_status_table[] = {
174 MGMT_STATUS_SUCCESS,
175 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
176 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
177 MGMT_STATUS_FAILED, /* Hardware Failure */
178 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200180 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200181 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
182 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
184 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
185 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
186 MGMT_STATUS_BUSY, /* Command Disallowed */
187 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
188 MGMT_STATUS_REJECTED, /* Rejected Security */
189 MGMT_STATUS_REJECTED, /* Rejected Personal */
190 MGMT_STATUS_TIMEOUT, /* Host Timeout */
191 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
192 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
193 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
194 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
195 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
196 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
197 MGMT_STATUS_BUSY, /* Repeated Attempts */
198 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
199 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
200 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
201 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
202 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
203 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
204 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
205 MGMT_STATUS_FAILED, /* Unspecified Error */
206 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
207 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
208 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
209 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
210 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
211 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
212 MGMT_STATUS_FAILED, /* Unit Link Key Used */
213 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
214 MGMT_STATUS_TIMEOUT, /* Instant Passed */
215 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
216 MGMT_STATUS_FAILED, /* Transaction Collision */
217 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
218 MGMT_STATUS_REJECTED, /* QoS Rejected */
219 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
220 MGMT_STATUS_REJECTED, /* Insufficient Security */
221 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
222 MGMT_STATUS_BUSY, /* Role Switch Pending */
223 MGMT_STATUS_FAILED, /* Slot Violation */
224 MGMT_STATUS_FAILED, /* Role Switch Failed */
225 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
226 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
227 MGMT_STATUS_BUSY, /* Host Busy Pairing */
228 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
229 MGMT_STATUS_BUSY, /* Controller Busy */
230 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
231 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
232 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
233 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
234 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
235};
236
237static u8 mgmt_status(u8 hci_status)
238{
239 if (hci_status < ARRAY_SIZE(mgmt_status_table))
240 return mgmt_status_table[hci_status];
241
242 return MGMT_STATUS_FAILED;
243}
244
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700245static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
246 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700247{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700248 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
249 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700250}
251
Marcel Holtmann72000df2015-03-16 16:11:21 -0700252static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
253 u16 len, int flag, struct sock *skip_sk)
254{
255 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
256 flag, skip_sk);
257}
258
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700259static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
260 u16 len, struct sock *skip_sk)
261{
262 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
263 HCI_MGMT_GENERIC_EVENTS, skip_sk);
264}
265
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200266static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
267 struct sock *skip_sk)
268{
269 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700270 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200271}
272
Johan Hedberg85813a72015-10-21 18:02:59 +0300273static u8 le_addr_type(u8 mgmt_addr_type)
274{
275 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
276 return ADDR_LE_DEV_PUBLIC;
277 else
278 return ADDR_LE_DEV_RANDOM;
279}
280
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200281void mgmt_fill_version_info(void *ver)
282{
283 struct mgmt_rp_read_version *rp = ver;
284
285 rp->version = MGMT_VERSION;
286 rp->revision = cpu_to_le16(MGMT_REVISION);
287}
288
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300289static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
290 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200291{
292 struct mgmt_rp_read_version rp;
293
294 BT_DBG("sock %p", sk);
295
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200296 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200297
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200298 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
299 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200300}
301
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300302static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
303 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304{
305 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700306 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307 size_t rp_size;
308 int i, err;
309
310 BT_DBG("sock %p", sk);
311
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700312 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
313 num_commands = ARRAY_SIZE(mgmt_commands);
314 num_events = ARRAY_SIZE(mgmt_events);
315 } else {
316 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
317 num_events = ARRAY_SIZE(mgmt_untrusted_events);
318 }
319
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
321
322 rp = kmalloc(rp_size, GFP_KERNEL);
323 if (!rp)
324 return -ENOMEM;
325
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700326 rp->num_commands = cpu_to_le16(num_commands);
327 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700329 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
330 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200331
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_events[i], opcode);
337 } else {
338 __le16 *opcode = rp->opcodes;
339
340 for (i = 0; i < num_commands; i++, opcode++)
341 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
342
343 for (i = 0; i < num_events; i++, opcode++)
344 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
345 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200347 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
348 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200349 kfree(rp);
350
351 return err;
352}
353
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300354static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
355 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200358 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200359 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300361 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200362
363 BT_DBG("sock %p", sk);
364
365 read_lock(&hci_dev_list_lock);
366
367 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300368 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200369 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700370 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700371 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372 }
373
Johan Hedberga38528f2011-01-22 06:46:43 +0200374 rp_len = sizeof(*rp) + (2 * count);
375 rp = kmalloc(rp_len, GFP_ATOMIC);
376 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100377 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100379 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380
Johan Hedberg476e44c2012-10-19 20:10:46 +0300381 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200382 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700383 if (hci_dev_test_flag(d, HCI_SETUP) ||
384 hci_dev_test_flag(d, HCI_CONFIG) ||
385 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200386 continue;
387
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200388 /* Devices marked as raw-only are neither configured
389 * nor unconfigured controllers.
390 */
391 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700392 continue;
393
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200394 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700395 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700396 rp->index[count++] = cpu_to_le16(d->id);
397 BT_DBG("Added hci%u", d->id);
398 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200399 }
400
Johan Hedberg476e44c2012-10-19 20:10:46 +0300401 rp->num_controllers = cpu_to_le16(count);
402 rp_len = sizeof(*rp) + (2 * count);
403
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404 read_unlock(&hci_dev_list_lock);
405
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200406 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
407 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200408
Johan Hedberga38528f2011-01-22 06:46:43 +0200409 kfree(rp);
410
411 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200412}
413
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200414static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
415 void *data, u16 data_len)
416{
417 struct mgmt_rp_read_unconf_index_list *rp;
418 struct hci_dev *d;
419 size_t rp_len;
420 u16 count;
421 int err;
422
423 BT_DBG("sock %p", sk);
424
425 read_lock(&hci_dev_list_lock);
426
427 count = 0;
428 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200429 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700430 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200431 count++;
432 }
433
434 rp_len = sizeof(*rp) + (2 * count);
435 rp = kmalloc(rp_len, GFP_ATOMIC);
436 if (!rp) {
437 read_unlock(&hci_dev_list_lock);
438 return -ENOMEM;
439 }
440
441 count = 0;
442 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700443 if (hci_dev_test_flag(d, HCI_SETUP) ||
444 hci_dev_test_flag(d, HCI_CONFIG) ||
445 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200446 continue;
447
448 /* Devices marked as raw-only are neither configured
449 * nor unconfigured controllers.
450 */
451 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
452 continue;
453
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200454 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700455 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200456 rp->index[count++] = cpu_to_le16(d->id);
457 BT_DBG("Added hci%u", d->id);
458 }
459 }
460
461 rp->num_controllers = cpu_to_le16(count);
462 rp_len = sizeof(*rp) + (2 * count);
463
464 read_unlock(&hci_dev_list_lock);
465
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200466 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
467 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200468
469 kfree(rp);
470
471 return err;
472}
473
Marcel Holtmann96f14742015-03-14 19:27:57 -0700474static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
475 void *data, u16 data_len)
476{
477 struct mgmt_rp_read_ext_index_list *rp;
478 struct hci_dev *d;
479 size_t rp_len;
480 u16 count;
481 int err;
482
483 BT_DBG("sock %p", sk);
484
485 read_lock(&hci_dev_list_lock);
486
487 count = 0;
488 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200489 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700490 count++;
491 }
492
493 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
494 rp = kmalloc(rp_len, GFP_ATOMIC);
495 if (!rp) {
496 read_unlock(&hci_dev_list_lock);
497 return -ENOMEM;
498 }
499
500 count = 0;
501 list_for_each_entry(d, &hci_dev_list, list) {
502 if (hci_dev_test_flag(d, HCI_SETUP) ||
503 hci_dev_test_flag(d, HCI_CONFIG) ||
504 hci_dev_test_flag(d, HCI_USER_CHANNEL))
505 continue;
506
507 /* Devices marked as raw-only are neither configured
508 * nor unconfigured controllers.
509 */
510 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
511 continue;
512
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200513 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700514 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
515 rp->entry[count].type = 0x01;
516 else
517 rp->entry[count].type = 0x00;
518 } else if (d->dev_type == HCI_AMP) {
519 rp->entry[count].type = 0x02;
520 } else {
521 continue;
522 }
523
524 rp->entry[count].bus = d->bus;
525 rp->entry[count++].index = cpu_to_le16(d->id);
526 BT_DBG("Added hci%u", d->id);
527 }
528
529 rp->num_controllers = cpu_to_le16(count);
530 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
531
532 read_unlock(&hci_dev_list_lock);
533
534 /* If this command is called at least once, then all the
535 * default index and unconfigured index events are disabled
536 * and from now on only extended index events are used.
537 */
538 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
539 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
540 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
541
542 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
543 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
544
545 kfree(rp);
546
547 return err;
548}
549
Marcel Holtmanndbece372014-07-04 18:11:55 +0200550static bool is_configured(struct hci_dev *hdev)
551{
552 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700553 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200554 return false;
555
556 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
557 !bacmp(&hdev->public_addr, BDADDR_ANY))
558 return false;
559
560 return true;
561}
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563static __le32 get_missing_options(struct hci_dev *hdev)
564{
565 u32 options = 0;
566
Marcel Holtmanndbece372014-07-04 18:11:55 +0200567 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700568 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200569 options |= MGMT_OPTION_EXTERNAL_CONFIG;
570
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200571 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
572 !bacmp(&hdev->public_addr, BDADDR_ANY))
573 options |= MGMT_OPTION_PUBLIC_ADDRESS;
574
575 return cpu_to_le32(options);
576}
577
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200578static int new_options(struct hci_dev *hdev, struct sock *skip)
579{
580 __le32 options = get_missing_options(hdev);
581
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700582 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
583 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200584}
585
Marcel Holtmanndbece372014-07-04 18:11:55 +0200586static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
587{
588 __le32 options = get_missing_options(hdev);
589
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200590 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
591 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200592}
593
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200594static int read_config_info(struct sock *sk, struct hci_dev *hdev,
595 void *data, u16 data_len)
596{
597 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200599
600 BT_DBG("sock %p %s", sk, hdev->name);
601
602 hci_dev_lock(hdev);
603
604 memset(&rp, 0, sizeof(rp));
605 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200606
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200607 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
608 options |= MGMT_OPTION_EXTERNAL_CONFIG;
609
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200610 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200611 options |= MGMT_OPTION_PUBLIC_ADDRESS;
612
613 rp.supported_options = cpu_to_le32(options);
614 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200615
616 hci_dev_unlock(hdev);
617
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200618 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
619 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200620}
621
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200623{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200624 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200625
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200626 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300627 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800628 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300629 settings |= MGMT_SETTING_CONNECTABLE;
630 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Andre Guedesed3fa312012-07-24 15:03:46 -0300632 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500633 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
634 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200635 settings |= MGMT_SETTING_BREDR;
636 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700637
638 if (lmp_ssp_capable(hdev)) {
639 settings |= MGMT_SETTING_SSP;
640 settings |= MGMT_SETTING_HS;
641 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800642
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800643 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800644 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700645 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100646
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300647 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200648 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300649 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300650 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200651 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800652 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300653 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200654
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200655 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
656 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200657 settings |= MGMT_SETTING_CONFIGURATION;
658
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659 return settings;
660}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200661
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662static u32 get_current_settings(struct hci_dev *hdev)
663{
664 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200665
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200666 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100667 settings |= MGMT_SETTING_POWERED;
668
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700669 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200670 settings |= MGMT_SETTING_CONNECTABLE;
671
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700672 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500673 settings |= MGMT_SETTING_FAST_CONNECTABLE;
674
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700675 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200676 settings |= MGMT_SETTING_DISCOVERABLE;
677
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700678 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300679 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700681 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200682 settings |= MGMT_SETTING_BREDR;
683
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700684 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200685 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200686
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700687 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200688 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200689
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700690 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200691 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200692
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700693 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200694 settings |= MGMT_SETTING_HS;
695
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700696 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300697 settings |= MGMT_SETTING_ADVERTISING;
698
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700699 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800700 settings |= MGMT_SETTING_SECURE_CONN;
701
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700702 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800703 settings |= MGMT_SETTING_DEBUG_KEYS;
704
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700705 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200706 settings |= MGMT_SETTING_PRIVACY;
707
Marcel Holtmann93690c22015-03-06 10:11:21 -0800708 /* The current setting for static address has two purposes. The
709 * first is to indicate if the static address will be used and
710 * the second is to indicate if it is actually set.
711 *
712 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700713 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 * address is actually used decides if the flag is set or not.
715 *
716 * For single mode LE only controllers and dual-mode controllers
717 * with BR/EDR disabled, the existence of the static address will
718 * be evaluated.
719 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700720 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700721 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800722 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
723 if (bacmp(&hdev->static_addr, BDADDR_ANY))
724 settings |= MGMT_SETTING_STATIC_ADDRESS;
725 }
726
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200727 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200728}
729
Johan Hedberg333ae952015-03-17 13:48:47 +0200730static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
731{
732 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
733}
734
Johan Hedberg333ae952015-03-17 13:48:47 +0200735static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
736 struct hci_dev *hdev,
737 const void *data)
738{
739 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
740}
741
Johan Hedbergf2252572015-11-18 12:49:20 +0200742u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300743{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200744 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300745
746 /* If there's a pending mgmt command the flags will not yet have
747 * their final values, so check for this first.
748 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200749 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300750 if (cmd) {
751 struct mgmt_mode *cp = cmd->param;
752 if (cp->val == 0x01)
753 return LE_AD_GENERAL;
754 else if (cp->val == 0x02)
755 return LE_AD_LIMITED;
756 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700757 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300758 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700759 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300760 return LE_AD_GENERAL;
761 }
762
763 return 0;
764}
765
Johan Hedbergf2252572015-11-18 12:49:20 +0200766bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700767{
768 struct mgmt_pending_cmd *cmd;
769
770 /* If there's a pending mgmt command the flag will not yet have
771 * it's final value, so check for this first.
772 */
773 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
774 if (cmd) {
775 struct mgmt_mode *cp = cmd->param;
776
777 return cp->val;
778 }
779
780 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
781}
782
Johan Hedberg7d785252011-12-15 00:47:39 +0200783static void service_cache_off(struct work_struct *work)
784{
785 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300786 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500787 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200788
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700789 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200790 return;
791
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 hci_req_init(&req, hdev);
793
Johan Hedberg7d785252011-12-15 00:47:39 +0200794 hci_dev_lock(hdev);
795
Johan Hedbergb1a89172015-11-25 16:15:42 +0200796 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200797 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200798
799 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500800
801 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200802}
803
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200804static void rpa_expired(struct work_struct *work)
805{
806 struct hci_dev *hdev = container_of(work, struct hci_dev,
807 rpa_expired.work);
808 struct hci_request req;
809
810 BT_DBG("");
811
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700812 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200813
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700814 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200815 return;
816
817 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200818 * controller happens in the hci_req_enable_advertising()
819 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200820 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200821 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200822 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200823 hci_req_run(&req, NULL);
824}
825
Johan Hedberg6a919082012-02-28 06:17:26 +0200826static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200827{
Marcel Holtmann238be782015-03-13 02:11:06 -0700828 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200829 return;
830
Johan Hedberg4f87da82012-03-02 19:55:56 +0200831 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200832 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833
Johan Hedberg4f87da82012-03-02 19:55:56 +0200834 /* Non-mgmt controlled devices get this bit set
835 * implicitly so that pairing works for them, however
836 * for mgmt we require user-space to explicitly enable
837 * it
838 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700839 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200840}
841
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200842static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300843 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
845 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200846
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200847 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 memset(&rp, 0, sizeof(rp));
852
Johan Hedberg03811012010-12-08 00:21:06 +0200853 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854
855 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200856 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200857
858 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
859 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
860
861 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862
863 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200864 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300866 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200867
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200868 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
869 sizeof(rp));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870}
871
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200873{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200875
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200876 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
877 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200878}
879
Marcel Holtmann1904a852015-01-11 13:50:44 -0800880static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200881{
882 BT_DBG("%s status 0x%02x", hdev->name, status);
883
Johan Hedberga3172b72014-02-28 09:33:44 +0200884 if (hci_conn_count(hdev) == 0) {
885 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200886 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200887 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200888}
889
Johan Hedbergf2252572015-11-18 12:49:20 +0200890void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700891{
892 struct mgmt_ev_advertising_added ev;
893
894 ev.instance = instance;
895
896 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
897}
898
Johan Hedbergf2252572015-11-18 12:49:20 +0200899void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
900 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700901{
902 struct mgmt_ev_advertising_removed ev;
903
904 ev.instance = instance;
905
906 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
907}
908
Florian Grandel7816b822015-06-18 03:16:45 +0200909static void cancel_adv_timeout(struct hci_dev *hdev)
910{
911 if (hdev->adv_instance_timeout) {
912 hdev->adv_instance_timeout = 0;
913 cancel_delayed_work(&hdev->adv_instance_expire);
914 }
915}
916
Johan Hedberg8b064a32014-02-24 14:52:22 +0200917static int clean_up_hci_state(struct hci_dev *hdev)
918{
919 struct hci_request req;
920 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300921 bool discov_stopped;
922 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200923
924 hci_req_init(&req, hdev);
925
926 if (test_bit(HCI_ISCAN, &hdev->flags) ||
927 test_bit(HCI_PSCAN, &hdev->flags)) {
928 u8 scan = 0x00;
929 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
930 }
931
Johan Hedbergf2252572015-11-18 12:49:20 +0200932 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -0700933
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700934 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +0200935 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200936
Johan Hedberg2154d3f2015-11-11 08:30:45 +0200937 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200938
939 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +0300940 /* 0x15 == Terminated due to Power Off */
941 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200942 }
943
Johan Hedberg23a48092014-07-08 16:05:06 +0300944 err = hci_req_run(&req, clean_up_hci_complete);
945 if (!err && discov_stopped)
946 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
947
948 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200949}
950
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200951static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300952 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300954 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200955 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200956 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
Johan Hedberga7e80f22013-01-09 16:05:19 +0200960 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +0200961 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
962 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +0200963
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300964 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
Johan Hedberg333ae952015-03-17 13:48:47 +0200966 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +0200967 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
968 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300969 goto failed;
970 }
971
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200972 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200973 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974 goto failed;
975 }
976
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
978 if (!cmd) {
979 err = -ENOMEM;
980 goto failed;
981 }
982
Johan Hedberg8b064a32014-02-24 14:52:22 +0200983 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +0200984 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200985 err = 0;
986 } else {
987 /* Disconnect connections, stop scans, etc */
988 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +0200989 if (!err)
990 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
991 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200992
Johan Hedberg8b064a32014-02-24 14:52:22 +0200993 /* ENODATA means there were no HCI commands queued */
994 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +0200995 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200996 queue_work(hdev->req_workqueue, &hdev->power_off.work);
997 err = 0;
998 }
999 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000
1001failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001002 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003 return err;
1004}
1005
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001006static int new_settings(struct hci_dev *hdev, struct sock *skip)
1007{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001008 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001009
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001010 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1011 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001012}
1013
Johan Hedberg91a668b2014-07-09 13:28:26 +03001014int mgmt_new_settings(struct hci_dev *hdev)
1015{
1016 return new_settings(hdev, NULL);
1017}
1018
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001019struct cmd_lookup {
1020 struct sock *sk;
1021 struct hci_dev *hdev;
1022 u8 mgmt_status;
1023};
1024
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001025static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001026{
1027 struct cmd_lookup *match = data;
1028
1029 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1030
1031 list_del(&cmd->list);
1032
1033 if (match->sk == NULL) {
1034 match->sk = cmd->sk;
1035 sock_hold(match->sk);
1036 }
1037
1038 mgmt_pending_free(cmd);
1039}
1040
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001041static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001042{
1043 u8 *status = data;
1044
Johan Hedberga69e8372015-03-06 21:08:53 +02001045 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001046 mgmt_pending_remove(cmd);
1047}
1048
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001049static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001050{
1051 if (cmd->cmd_complete) {
1052 u8 *status = data;
1053
1054 cmd->cmd_complete(cmd, *status);
1055 mgmt_pending_remove(cmd);
1056
1057 return;
1058 }
1059
1060 cmd_status_rsp(cmd, data);
1061}
1062
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001063static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001064{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001065 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1066 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001067}
1068
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001069static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001070{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001071 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1072 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001073}
1074
Johan Hedberge6fe7982013-10-02 15:45:22 +03001075static u8 mgmt_bredr_support(struct hci_dev *hdev)
1076{
1077 if (!lmp_bredr_capable(hdev))
1078 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001079 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001080 return MGMT_STATUS_REJECTED;
1081 else
1082 return MGMT_STATUS_SUCCESS;
1083}
1084
1085static u8 mgmt_le_support(struct hci_dev *hdev)
1086{
1087 if (!lmp_le_capable(hdev))
1088 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001089 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001090 return MGMT_STATUS_REJECTED;
1091 else
1092 return MGMT_STATUS_SUCCESS;
1093}
1094
Johan Hedbergaed1a882015-11-22 17:24:44 +03001095void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001096{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001097 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001098
1099 BT_DBG("status 0x%02x", status);
1100
1101 hci_dev_lock(hdev);
1102
Johan Hedberg333ae952015-03-17 13:48:47 +02001103 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001104 if (!cmd)
1105 goto unlock;
1106
1107 if (status) {
1108 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001109 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001110 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001111 goto remove_cmd;
1112 }
1113
Johan Hedbergaed1a882015-11-22 17:24:44 +03001114 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1115 hdev->discov_timeout > 0) {
1116 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1117 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001118 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001119
1120 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001121 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001122
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001123remove_cmd:
1124 mgmt_pending_remove(cmd);
1125
1126unlock:
1127 hci_dev_unlock(hdev);
1128}
1129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001130static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001131 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001133 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001134 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001136 int err;
1137
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001138 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001139
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001140 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1141 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001142 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1143 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001144
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001145 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001146 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1147 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001148
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001149 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001150
1151 /* Disabling discoverable requires that no timeout is set,
1152 * and enabling limited discoverable requires a timeout.
1153 */
1154 if ((cp->val == 0x00 && timeout > 0) ||
1155 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001156 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001159 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001160
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001161 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001162 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1163 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 goto failed;
1165 }
1166
Johan Hedberg333ae952015-03-17 13:48:47 +02001167 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1168 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001169 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1170 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001171 goto failed;
1172 }
1173
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001174 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001175 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1176 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001177 goto failed;
1178 }
1179
1180 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001181 bool changed = false;
1182
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001183 /* Setting limited discoverable when powered off is
1184 * not a valid operation since it requires a timeout
1185 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1186 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001187 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001188 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001189 changed = true;
1190 }
1191
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001192 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001193 if (err < 0)
1194 goto failed;
1195
1196 if (changed)
1197 err = new_settings(hdev, sk);
1198
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001199 goto failed;
1200 }
1201
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001202 /* If the current mode is the same, then just update the timeout
1203 * value with the new value. And if only the timeout gets updated,
1204 * then no need for any HCI transactions.
1205 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001206 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1207 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1208 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001209 cancel_delayed_work(&hdev->discov_off);
1210 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001211
Marcel Holtmann36261542013-10-15 08:28:51 -07001212 if (cp->val && hdev->discov_timeout > 0) {
1213 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001214 queue_delayed_work(hdev->req_workqueue,
1215 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001216 }
1217
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001218 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219 goto failed;
1220 }
1221
1222 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1223 if (!cmd) {
1224 err = -ENOMEM;
1225 goto failed;
1226 }
1227
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001228 /* Cancel any potential discoverable timeout that might be
1229 * still active and store new timeout value. The arming of
1230 * the timeout happens in the complete handler.
1231 */
1232 cancel_delayed_work(&hdev->discov_off);
1233 hdev->discov_timeout = timeout;
1234
Johan Hedbergaed1a882015-11-22 17:24:44 +03001235 if (cp->val)
1236 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1237 else
1238 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1239
Johan Hedbergb456f872013-10-19 23:38:22 +03001240 /* Limited discoverable mode */
1241 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001242 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001243 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001244 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001245
Johan Hedbergaed1a882015-11-22 17:24:44 +03001246 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1247 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001248
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001249failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001250 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001251 return err;
1252}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001253
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001254void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001255{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001256 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001257
1258 BT_DBG("status 0x%02x", status);
1259
1260 hci_dev_lock(hdev);
1261
Johan Hedberg333ae952015-03-17 13:48:47 +02001262 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001263 if (!cmd)
1264 goto unlock;
1265
Johan Hedberg37438c12013-10-14 16:20:05 +03001266 if (status) {
1267 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001268 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001269 goto remove_cmd;
1270 }
1271
Johan Hedberg2b76f452013-03-15 17:07:04 -05001272 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001273 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001274
Johan Hedberg37438c12013-10-14 16:20:05 +03001275remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001276 mgmt_pending_remove(cmd);
1277
1278unlock:
1279 hci_dev_unlock(hdev);
1280}
1281
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001282static int set_connectable_update_settings(struct hci_dev *hdev,
1283 struct sock *sk, u8 val)
1284{
1285 bool changed = false;
1286 int err;
1287
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001288 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001289 changed = true;
1290
1291 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001292 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001293 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001294 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1295 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001296 }
1297
1298 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1299 if (err < 0)
1300 return err;
1301
Johan Hedberg562064e2014-07-08 16:35:34 +03001302 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001303 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001304 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001305 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001306 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001307
1308 return 0;
1309}
1310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001312 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001313{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001314 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001315 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001316 int err;
1317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001319
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001320 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1321 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001322 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1323 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001324
Johan Hedberga7e80f22013-01-09 16:05:19 +02001325 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001326 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1327 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001329 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001330
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001331 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001332 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001333 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001334 }
1335
Johan Hedberg333ae952015-03-17 13:48:47 +02001336 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1337 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001338 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1339 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001340 goto failed;
1341 }
1342
Johan Hedberg73f22f62010-12-29 16:00:25 +02001343 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1344 if (!cmd) {
1345 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001346 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001347 }
1348
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001349 if (cp->val) {
1350 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1351 } else {
1352 if (hdev->discov_timeout > 0)
1353 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001354
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001355 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1356 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1357 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001358 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001359
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001360 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1361 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001362
1363failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001364 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001365 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001366}
1367
Johan Hedbergb2939472014-07-30 09:22:23 +03001368static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001369 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001370{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001371 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001372 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001373 int err;
1374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001375 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001376
Johan Hedberga7e80f22013-01-09 16:05:19 +02001377 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001378 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001381 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001382
1383 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001384 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001385 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001386 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001387
Johan Hedbergb2939472014-07-30 09:22:23 +03001388 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001389 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001390 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001391
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001392 if (changed) {
1393 /* In limited privacy mode the change of bondable mode
1394 * may affect the local advertising address.
1395 */
1396 if (hdev_is_powered(hdev) &&
1397 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1398 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1399 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1400 queue_work(hdev->req_workqueue,
1401 &hdev->discoverable_update);
1402
Marcel Holtmann55594352013-10-06 16:11:57 -07001403 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001404 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001405
Marcel Holtmann55594352013-10-06 16:11:57 -07001406unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001407 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001408 return err;
1409}
1410
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001411static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1412 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001413{
1414 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001415 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001416 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001417 int err;
1418
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001419 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001420
Johan Hedberge6fe7982013-10-02 15:45:22 +03001421 status = mgmt_bredr_support(hdev);
1422 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1424 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001425
Johan Hedberga7e80f22013-01-09 16:05:19 +02001426 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001427 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1428 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001429
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001430 hci_dev_lock(hdev);
1431
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001432 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001433 bool changed = false;
1434
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001435 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001436 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001437 changed = true;
1438 }
1439
1440 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1441 if (err < 0)
1442 goto failed;
1443
1444 if (changed)
1445 err = new_settings(hdev, sk);
1446
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001447 goto failed;
1448 }
1449
Johan Hedberg333ae952015-03-17 13:48:47 +02001450 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001451 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1452 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001453 goto failed;
1454 }
1455
1456 val = !!cp->val;
1457
1458 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1459 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1460 goto failed;
1461 }
1462
1463 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1464 if (!cmd) {
1465 err = -ENOMEM;
1466 goto failed;
1467 }
1468
1469 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1470 if (err < 0) {
1471 mgmt_pending_remove(cmd);
1472 goto failed;
1473 }
1474
1475failed:
1476 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001477 return err;
1478}
1479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001480static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001481{
1482 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001483 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001484 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001485 int err;
1486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001487 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001488
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001489 status = mgmt_bredr_support(hdev);
1490 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001491 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001492
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001493 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001494 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1495 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001496
Johan Hedberga7e80f22013-01-09 16:05:19 +02001497 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001498 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1499 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001500
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001501 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001502
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001503 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001504 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001505
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001506 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001507 changed = !hci_dev_test_and_set_flag(hdev,
1508 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001509 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001510 changed = hci_dev_test_and_clear_flag(hdev,
1511 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001512 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001513 changed = hci_dev_test_and_clear_flag(hdev,
1514 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001515 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001516 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001517 }
1518
1519 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1520 if (err < 0)
1521 goto failed;
1522
1523 if (changed)
1524 err = new_settings(hdev, sk);
1525
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001526 goto failed;
1527 }
1528
Johan Hedberg333ae952015-03-17 13:48:47 +02001529 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001530 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1531 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001532 goto failed;
1533 }
1534
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001535 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001536 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1537 goto failed;
1538 }
1539
1540 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1541 if (!cmd) {
1542 err = -ENOMEM;
1543 goto failed;
1544 }
1545
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001546 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001547 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1548 sizeof(cp->val), &cp->val);
1549
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001550 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001551 if (err < 0) {
1552 mgmt_pending_remove(cmd);
1553 goto failed;
1554 }
1555
1556failed:
1557 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001558 return err;
1559}
1560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001562{
1563 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001564 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001565 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001566 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001567
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001568 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001569
Johan Hedberge6fe7982013-10-02 15:45:22 +03001570 status = mgmt_bredr_support(hdev);
1571 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001573
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001574 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001575 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1576 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001577
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001578 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001579 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1580 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001581
Johan Hedberga7e80f22013-01-09 16:05:19 +02001582 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001583 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1584 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001585
Marcel Holtmannee392692013-10-01 22:59:23 -07001586 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001587
Johan Hedberg333ae952015-03-17 13:48:47 +02001588 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001589 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1590 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001591 goto unlock;
1592 }
1593
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001594 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001595 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001596 } else {
1597 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001598 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1599 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001600 goto unlock;
1601 }
1602
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001603 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001604 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001605
1606 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1607 if (err < 0)
1608 goto unlock;
1609
1610 if (changed)
1611 err = new_settings(hdev, sk);
1612
1613unlock:
1614 hci_dev_unlock(hdev);
1615 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001616}
1617
Marcel Holtmann1904a852015-01-11 13:50:44 -08001618static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001619{
1620 struct cmd_lookup match = { NULL, hdev };
1621
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301622 hci_dev_lock(hdev);
1623
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001624 if (status) {
1625 u8 mgmt_err = mgmt_status(status);
1626
1627 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1628 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301629 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001630 }
1631
1632 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1633
1634 new_settings(hdev, match.sk);
1635
1636 if (match.sk)
1637 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001638
1639 /* Make sure the controller has a good default for
1640 * advertising data. Restrict the update to when LE
1641 * has actually been enabled. During power on, the
1642 * update in powered_update_hci will take care of it.
1643 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001644 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001645 struct hci_request req;
1646
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001647 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001648 __hci_req_update_adv_data(&req, 0x00);
1649 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001650 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001651 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001652 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301653
1654unlock:
1655 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001656}
1657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001659{
1660 struct mgmt_mode *cp = data;
1661 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001662 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001663 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001664 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001665 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001667 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001668
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001669 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1671 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001672
Johan Hedberga7e80f22013-01-09 16:05:19 +02001673 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1675 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001676
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001677 /* Bluetooth single mode LE only controllers or dual-mode
1678 * controllers configured as LE only devices, do not allow
1679 * switching LE off. These have either LE enabled explicitly
1680 * or BR/EDR has been previously switched off.
1681 *
1682 * When trying to enable an already enabled LE, then gracefully
1683 * send a positive response. Trying to disable it however will
1684 * result into rejection.
1685 */
1686 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1687 if (cp->val == 0x01)
1688 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1689
Johan Hedberga69e8372015-03-06 21:08:53 +02001690 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1691 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001692 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001693
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001694 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001695
1696 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001697 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001698
Florian Grandel847818d2015-06-18 03:16:46 +02001699 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001700 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001701
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001702 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001703 bool changed = false;
1704
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001705 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001706 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001707 changed = true;
1708 }
1709
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001710 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001711 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001712 changed = true;
1713 }
1714
Johan Hedberg06199cf2012-02-22 16:37:11 +02001715 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1716 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001717 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001718
1719 if (changed)
1720 err = new_settings(hdev, sk);
1721
Johan Hedberg1de028c2012-02-29 19:55:35 -08001722 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001723 }
1724
Johan Hedberg333ae952015-03-17 13:48:47 +02001725 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1726 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1728 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001729 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001730 }
1731
1732 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1733 if (!cmd) {
1734 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001735 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001736 }
1737
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001738 hci_req_init(&req, hdev);
1739
Johan Hedberg06199cf2012-02-22 16:37:11 +02001740 memset(&hci_cp, 0, sizeof(hci_cp));
1741
1742 if (val) {
1743 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001744 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001745 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001746 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001747 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001748 }
1749
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001750 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1751 &hci_cp);
1752
1753 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301754 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001755 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001756
Johan Hedberg1de028c2012-02-29 19:55:35 -08001757unlock:
1758 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001759 return err;
1760}
1761
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001762/* This is a helper function to test for pending mgmt commands that can
1763 * cause CoD or EIR HCI commands. We can only allow one such pending
1764 * mgmt command at a time since otherwise we cannot easily track what
1765 * the current values are, will be, and based on that calculate if a new
1766 * HCI command needs to be sent and if yes with what value.
1767 */
1768static bool pending_eir_or_class(struct hci_dev *hdev)
1769{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001770 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001771
1772 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1773 switch (cmd->opcode) {
1774 case MGMT_OP_ADD_UUID:
1775 case MGMT_OP_REMOVE_UUID:
1776 case MGMT_OP_SET_DEV_CLASS:
1777 case MGMT_OP_SET_POWERED:
1778 return true;
1779 }
1780 }
1781
1782 return false;
1783}
1784
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001785static const u8 bluetooth_base_uuid[] = {
1786 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1787 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1788};
1789
1790static u8 get_uuid_size(const u8 *uuid)
1791{
1792 u32 val;
1793
1794 if (memcmp(uuid, bluetooth_base_uuid, 12))
1795 return 128;
1796
1797 val = get_unaligned_le32(&uuid[12]);
1798 if (val > 0xffff)
1799 return 32;
1800
1801 return 16;
1802}
1803
Johan Hedberg92da6092013-03-15 17:06:55 -05001804static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1805{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001806 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001807
1808 hci_dev_lock(hdev);
1809
Johan Hedberg333ae952015-03-17 13:48:47 +02001810 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001811 if (!cmd)
1812 goto unlock;
1813
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001814 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1815 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001816
1817 mgmt_pending_remove(cmd);
1818
1819unlock:
1820 hci_dev_unlock(hdev);
1821}
1822
Marcel Holtmann1904a852015-01-11 13:50:44 -08001823static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001824{
1825 BT_DBG("status 0x%02x", status);
1826
1827 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1828}
1829
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001830static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001831{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001832 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001833 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001834 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001835 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001836 int err;
1837
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001838 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001839
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001840 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001841
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001842 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001843 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1844 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001845 goto failed;
1846 }
1847
Andre Guedes92c4c202012-06-07 19:05:44 -03001848 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001849 if (!uuid) {
1850 err = -ENOMEM;
1851 goto failed;
1852 }
1853
1854 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001855 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001856 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001857
Johan Hedbergde66aa62013-01-27 00:31:27 +02001858 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001859
Johan Hedberg890ea892013-03-15 17:06:52 -05001860 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001861
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001862 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001863 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001864
Johan Hedberg92da6092013-03-15 17:06:55 -05001865 err = hci_req_run(&req, add_uuid_complete);
1866 if (err < 0) {
1867 if (err != -ENODATA)
1868 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001869
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001870 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1871 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001872 goto failed;
1873 }
1874
1875 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001876 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001877 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001878 goto failed;
1879 }
1880
1881 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001882
1883failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001884 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001885 return err;
1886}
1887
Johan Hedberg24b78d02012-02-23 23:24:30 +02001888static bool enable_service_cache(struct hci_dev *hdev)
1889{
1890 if (!hdev_is_powered(hdev))
1891 return false;
1892
Marcel Holtmann238be782015-03-13 02:11:06 -07001893 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001894 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1895 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001896 return true;
1897 }
1898
1899 return false;
1900}
1901
Marcel Holtmann1904a852015-01-11 13:50:44 -08001902static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001903{
1904 BT_DBG("status 0x%02x", status);
1905
1906 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1907}
1908
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001909static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001910 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001911{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001912 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001913 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001914 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001915 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001916 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001917 int err, found;
1918
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001919 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001920
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001921 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001922
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001923 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001924 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1925 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001926 goto unlock;
1927 }
1928
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001929 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02001930 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001931
Johan Hedberg24b78d02012-02-23 23:24:30 +02001932 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001933 err = mgmt_cmd_complete(sk, hdev->id,
1934 MGMT_OP_REMOVE_UUID,
1935 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001936 goto unlock;
1937 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001938
Johan Hedberg9246a862012-02-23 21:33:16 +02001939 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001940 }
1941
1942 found = 0;
1943
Johan Hedberg056341c2013-01-27 00:31:30 +02001944 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001945 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1946 continue;
1947
1948 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001949 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001950 found++;
1951 }
1952
1953 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001954 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1955 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001956 goto unlock;
1957 }
1958
Johan Hedberg9246a862012-02-23 21:33:16 +02001959update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001960 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001961
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001962 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001963 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001964
Johan Hedberg92da6092013-03-15 17:06:55 -05001965 err = hci_req_run(&req, remove_uuid_complete);
1966 if (err < 0) {
1967 if (err != -ENODATA)
1968 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001969
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
1971 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001972 goto unlock;
1973 }
1974
1975 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001976 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001977 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001978 goto unlock;
1979 }
1980
1981 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001982
1983unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001984 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985 return err;
1986}
1987
Marcel Holtmann1904a852015-01-11 13:50:44 -08001988static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001989{
1990 BT_DBG("status 0x%02x", status);
1991
1992 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1993}
1994
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001997{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001998 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001999 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002000 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002001 int err;
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002004
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002005 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002006 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2007 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002008
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002009 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002010
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002011 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002012 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2013 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002014 goto unlock;
2015 }
2016
2017 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002018 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2019 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002020 goto unlock;
2021 }
2022
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002023 hdev->major_class = cp->major;
2024 hdev->minor_class = cp->minor;
2025
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002026 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002027 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2028 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002029 goto unlock;
2030 }
2031
Johan Hedberg890ea892013-03-15 17:06:52 -05002032 hci_req_init(&req, hdev);
2033
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002034 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002035 hci_dev_unlock(hdev);
2036 cancel_delayed_work_sync(&hdev->service_cache);
2037 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002038 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002039 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002040
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002041 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002042
Johan Hedberg92da6092013-03-15 17:06:55 -05002043 err = hci_req_run(&req, set_class_complete);
2044 if (err < 0) {
2045 if (err != -ENODATA)
2046 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002047
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002048 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2049 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002050 goto unlock;
2051 }
2052
2053 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002054 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002055 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002056 goto unlock;
2057 }
2058
2059 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002060
Johan Hedbergb5235a62012-02-21 14:32:24 +02002061unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002062 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002063 return err;
2064}
2065
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002066static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002067 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002068{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002069 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002070 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2071 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002072 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002073 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002074 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002075
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002076 BT_DBG("request for %s", hdev->name);
2077
2078 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002079 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2080 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002081
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002082 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002083 if (key_count > max_key_count) {
2084 BT_ERR("load_link_keys: too big key_count value %u",
2085 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002086 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2087 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002088 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002089
Johan Hedberg86742e12011-11-07 23:13:38 +02002090 expected_len = sizeof(*cp) + key_count *
2091 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002092 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002093 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002094 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002095 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2096 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002097 }
2098
Johan Hedberg4ae14302013-01-20 14:27:13 +02002099 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002100 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2101 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002104 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002105
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002106 for (i = 0; i < key_count; i++) {
2107 struct mgmt_link_key_info *key = &cp->keys[i];
2108
Marcel Holtmann8e991132014-01-10 02:07:25 -08002109 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002110 return mgmt_cmd_status(sk, hdev->id,
2111 MGMT_OP_LOAD_LINK_KEYS,
2112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002113 }
2114
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002115 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002116
2117 hci_link_keys_clear(hdev);
2118
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002119 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002120 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002121 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002122 changed = hci_dev_test_and_clear_flag(hdev,
2123 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002124
2125 if (changed)
2126 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002127
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002128 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002129 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002130
Johan Hedberg58e92932014-06-24 14:00:26 +03002131 /* Always ignore debug keys and require a new pairing if
2132 * the user wants to use them.
2133 */
2134 if (key->type == HCI_LK_DEBUG_COMBINATION)
2135 continue;
2136
Johan Hedberg7652ff62014-06-24 13:15:49 +03002137 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2138 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002139 }
2140
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002141 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002143 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002144
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002145 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002146}
2147
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002148static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002149 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002150{
2151 struct mgmt_ev_device_unpaired ev;
2152
2153 bacpy(&ev.addr.bdaddr, bdaddr);
2154 ev.addr.type = addr_type;
2155
2156 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002158}
2159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002160static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002162{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002163 struct mgmt_cp_unpair_device *cp = data;
2164 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002165 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002166 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002167 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002168 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002169 int err;
2170
Johan Hedberga8a1d192011-11-10 15:54:38 +02002171 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002172 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2173 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002174
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002175 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002176 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2177 MGMT_STATUS_INVALID_PARAMS,
2178 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002179
Johan Hedberg118da702013-01-20 14:27:20 +02002180 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002181 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2182 MGMT_STATUS_INVALID_PARAMS,
2183 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002184
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002185 hci_dev_lock(hdev);
2186
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002187 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002188 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2189 MGMT_STATUS_NOT_POWERED, &rp,
2190 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002191 goto unlock;
2192 }
2193
Johan Hedberge0b2b272014-02-18 17:14:31 +02002194 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002195 /* If disconnection is requested, then look up the
2196 * connection. If the remote device is connected, it
2197 * will be later used to terminate the link.
2198 *
2199 * Setting it to NULL explicitly will cause no
2200 * termination of the link.
2201 */
2202 if (cp->disconnect)
2203 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2204 &cp->addr.bdaddr);
2205 else
2206 conn = NULL;
2207
Johan Hedberg124f6e32012-02-09 13:50:12 +02002208 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002209 if (err < 0) {
2210 err = mgmt_cmd_complete(sk, hdev->id,
2211 MGMT_OP_UNPAIR_DEVICE,
2212 MGMT_STATUS_NOT_PAIRED, &rp,
2213 sizeof(rp));
2214 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002215 }
2216
Johan Hedbergec182f02015-10-21 18:03:03 +03002217 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002218 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002219
Johan Hedbergec182f02015-10-21 18:03:03 +03002220 /* LE address type */
2221 addr_type = le_addr_type(cp->addr.type);
2222
2223 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2224
2225 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002226 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002227 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2228 MGMT_STATUS_NOT_PAIRED, &rp,
2229 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002230 goto unlock;
2231 }
2232
Johan Hedbergec182f02015-10-21 18:03:03 +03002233 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2234 if (!conn) {
2235 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2236 goto done;
2237 }
2238
Johan Hedbergc81d5552015-10-22 09:38:35 +03002239 /* Abort any ongoing SMP pairing */
2240 smp_cancel_pairing(conn);
2241
Johan Hedbergec182f02015-10-21 18:03:03 +03002242 /* Defer clearing up the connection parameters until closing to
2243 * give a chance of keeping them if a repairing happens.
2244 */
2245 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2246
Johan Hedbergfc643612015-10-22 09:38:31 +03002247 /* Disable auto-connection parameters if present */
2248 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2249 if (params) {
2250 if (params->explicit_connect)
2251 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2252 else
2253 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2254 }
2255
Johan Hedbergec182f02015-10-21 18:03:03 +03002256 /* If disconnection is not requested, then clear the connection
2257 * variable so that the link is not terminated.
2258 */
2259 if (!cp->disconnect)
2260 conn = NULL;
2261
2262done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002263 /* If the connection variable is set, then termination of the
2264 * link is requested.
2265 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002266 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002267 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2268 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002269 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002270 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002271 }
2272
Johan Hedberg124f6e32012-02-09 13:50:12 +02002273 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002275 if (!cmd) {
2276 err = -ENOMEM;
2277 goto unlock;
2278 }
2279
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002280 cmd->cmd_complete = addr_cmd_complete;
2281
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002282 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002283 if (err < 0)
2284 mgmt_pending_remove(cmd);
2285
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002286unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002287 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002288 return err;
2289}
2290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002292 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002293{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002294 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002295 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002296 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002297 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002298 int err;
2299
2300 BT_DBG("");
2301
Johan Hedberg06a63b12013-01-20 14:27:21 +02002302 memset(&rp, 0, sizeof(rp));
2303 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2304 rp.addr.type = cp->addr.type;
2305
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002306 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002307 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2308 MGMT_STATUS_INVALID_PARAMS,
2309 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002310
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002311 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002312
2313 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002314 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2315 MGMT_STATUS_NOT_POWERED, &rp,
2316 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002317 goto failed;
2318 }
2319
Johan Hedberg333ae952015-03-17 13:48:47 +02002320 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002321 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2322 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002323 goto failed;
2324 }
2325
Andre Guedes591f47f2012-04-24 21:02:49 -03002326 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002327 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2328 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002329 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002330 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2331 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002332
Vishal Agarwalf9607272012-06-13 05:32:43 +05302333 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2335 MGMT_STATUS_NOT_CONNECTED, &rp,
2336 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002337 goto failed;
2338 }
2339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002340 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002341 if (!cmd) {
2342 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002343 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002344 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002345
Johan Hedbergf5818c22014-12-05 13:36:02 +02002346 cmd->cmd_complete = generic_cmd_complete;
2347
Johan Hedberge3f2f922014-08-18 20:33:33 +03002348 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002349 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002350 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002351
2352failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002353 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002354 return err;
2355}
2356
Andre Guedes57c14772012-04-24 21:02:50 -03002357static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002358{
2359 switch (link_type) {
2360 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002361 switch (addr_type) {
2362 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002363 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002364
Johan Hedberg48264f02011-11-09 13:58:58 +02002365 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002366 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002367 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002368 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002369
Johan Hedberg4c659c32011-11-07 23:13:39 +02002370 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002371 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002372 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002373 }
2374}
2375
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2377 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002378{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002379 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002380 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002381 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002382 int err;
2383 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002384
2385 BT_DBG("");
2386
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002387 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002388
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002389 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002390 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2391 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002392 goto unlock;
2393 }
2394
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002395 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002396 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2397 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002398 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002399 }
2400
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002401 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002402 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002403 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002404 err = -ENOMEM;
2405 goto unlock;
2406 }
2407
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002409 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002410 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2411 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002412 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002413 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002414 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002415 continue;
2416 i++;
2417 }
2418
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002419 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002420
Johan Hedberg4c659c32011-11-07 23:13:39 +02002421 /* Recalculate length in case of filtered SCO connections, etc */
2422 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002423
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002424 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2425 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002426
Johan Hedberga38528f2011-01-22 06:46:43 +02002427 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002428
2429unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002430 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002431 return err;
2432}
2433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002436{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002437 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002438 int err;
2439
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002440 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002441 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002442 if (!cmd)
2443 return -ENOMEM;
2444
Johan Hedbergd8457692012-02-17 14:24:57 +02002445 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002446 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002447 if (err < 0)
2448 mgmt_pending_remove(cmd);
2449
2450 return err;
2451}
2452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002453static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002454 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002455{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002456 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002458 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002459 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002460 int err;
2461
2462 BT_DBG("");
2463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002464 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002466 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002467 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2468 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469 goto failed;
2470 }
2471
Johan Hedbergd8457692012-02-17 14:24:57 +02002472 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002473 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002474 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2475 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002476 goto failed;
2477 }
2478
2479 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002480 struct mgmt_cp_pin_code_neg_reply ncp;
2481
2482 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002483
2484 BT_ERR("PIN code is not 16 bytes long");
2485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002487 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002488 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2489 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002490
2491 goto failed;
2492 }
2493
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002494 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002495 if (!cmd) {
2496 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002497 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002498 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002499
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002500 cmd->cmd_complete = addr_cmd_complete;
2501
Johan Hedbergd8457692012-02-17 14:24:57 +02002502 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002503 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002504 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505
2506 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2507 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002508 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002509
2510failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002511 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002512 return err;
2513}
2514
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002515static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2516 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002517{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002518 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002519
2520 BT_DBG("");
2521
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002522 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002523 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2524 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002526 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002527
2528 hdev->io_capability = cp->io_capability;
2529
2530 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002531 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002533 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002534
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002535 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2536 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002537}
2538
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002539static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002540{
2541 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002542 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002543
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002544 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002545 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2546 continue;
2547
Johan Hedberge9a416b2011-02-19 12:05:56 -03002548 if (cmd->user_data != conn)
2549 continue;
2550
2551 return cmd;
2552 }
2553
2554 return NULL;
2555}
2556
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002557static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002558{
2559 struct mgmt_rp_pair_device rp;
2560 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002561 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002562
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002563 bacpy(&rp.addr.bdaddr, &conn->dst);
2564 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002565
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002566 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2567 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002568
2569 /* So we don't get further callbacks for this connection */
2570 conn->connect_cfm_cb = NULL;
2571 conn->security_cfm_cb = NULL;
2572 conn->disconn_cfm_cb = NULL;
2573
David Herrmann76a68ba2013-04-06 20:28:37 +02002574 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002575
2576 /* The device is paired so there is no need to remove
2577 * its connection parameters anymore.
2578 */
2579 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002580
2581 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002582
2583 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002584}
2585
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002586void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2587{
2588 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002589 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002590
2591 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002592 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002593 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002594 mgmt_pending_remove(cmd);
2595 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002596}
2597
Johan Hedberge9a416b2011-02-19 12:05:56 -03002598static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2599{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002600 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002601
2602 BT_DBG("status %u", status);
2603
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002604 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002605 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002606 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002607 return;
2608 }
2609
2610 cmd->cmd_complete(cmd, mgmt_status(status));
2611 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002612}
2613
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002614static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302615{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002616 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302617
2618 BT_DBG("status %u", status);
2619
2620 if (!status)
2621 return;
2622
2623 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002624 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302625 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002626 return;
2627 }
2628
2629 cmd->cmd_complete(cmd, mgmt_status(status));
2630 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302631}
2632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002633static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002635{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002636 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002637 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002638 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002639 u8 sec_level, auth_type;
2640 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641 int err;
2642
2643 BT_DBG("");
2644
Szymon Jancf950a30e2013-01-18 12:48:07 +01002645 memset(&rp, 0, sizeof(rp));
2646 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2647 rp.addr.type = cp->addr.type;
2648
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002649 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002650 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2651 MGMT_STATUS_INVALID_PARAMS,
2652 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002653
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002654 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002655 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2656 MGMT_STATUS_INVALID_PARAMS,
2657 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002659 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002660
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002661 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002662 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2663 MGMT_STATUS_NOT_POWERED, &rp,
2664 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002665 goto unlock;
2666 }
2667
Johan Hedberg55e76b32015-03-10 22:34:40 +02002668 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2669 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2670 MGMT_STATUS_ALREADY_PAIRED, &rp,
2671 sizeof(rp));
2672 goto unlock;
2673 }
2674
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002675 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002676 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002677
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002678 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002679 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2680 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002681 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002682 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002683 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002684
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002685 /* When pairing a new device, it is expected to remember
2686 * this device for future connections. Adding the connection
2687 * parameter information ahead of time allows tracking
2688 * of the slave preferred values and will speed up any
2689 * further connection establishment.
2690 *
2691 * If connection parameters already exist, then they
2692 * will be kept and this function does nothing.
2693 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002694 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2695
2696 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2697 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002698
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002699 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2700 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002701 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002702 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002703
Ville Tervo30e76272011-02-22 16:10:53 -03002704 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002705 int status;
2706
2707 if (PTR_ERR(conn) == -EBUSY)
2708 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002709 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2710 status = MGMT_STATUS_NOT_SUPPORTED;
2711 else if (PTR_ERR(conn) == -ECONNREFUSED)
2712 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002713 else
2714 status = MGMT_STATUS_CONNECT_FAILED;
2715
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002716 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2717 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002718 goto unlock;
2719 }
2720
2721 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002722 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002723 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2724 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002725 goto unlock;
2726 }
2727
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002728 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 if (!cmd) {
2730 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002731 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732 goto unlock;
2733 }
2734
Johan Hedberg04ab2742014-12-05 13:36:04 +02002735 cmd->cmd_complete = pairing_complete;
2736
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002737 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002738 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002739 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002740 conn->security_cfm_cb = pairing_complete_cb;
2741 conn->disconn_cfm_cb = pairing_complete_cb;
2742 } else {
2743 conn->connect_cfm_cb = le_pairing_complete_cb;
2744 conn->security_cfm_cb = le_pairing_complete_cb;
2745 conn->disconn_cfm_cb = le_pairing_complete_cb;
2746 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002747
Johan Hedberge9a416b2011-02-19 12:05:56 -03002748 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002749 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002750
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002751 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002752 hci_conn_security(conn, sec_level, auth_type, true)) {
2753 cmd->cmd_complete(cmd, 0);
2754 mgmt_pending_remove(cmd);
2755 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756
2757 err = 0;
2758
2759unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002760 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 return err;
2762}
2763
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002764static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2765 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002766{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002767 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002768 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002769 struct hci_conn *conn;
2770 int err;
2771
2772 BT_DBG("");
2773
Johan Hedberg28424702012-02-02 04:02:29 +02002774 hci_dev_lock(hdev);
2775
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002776 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002777 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2778 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002779 goto unlock;
2780 }
2781
Johan Hedberg333ae952015-03-17 13:48:47 +02002782 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002783 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002784 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2785 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002786 goto unlock;
2787 }
2788
2789 conn = cmd->user_data;
2790
2791 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002792 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2793 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002794 goto unlock;
2795 }
2796
Johan Hedberga511b352014-12-11 21:45:45 +02002797 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2798 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002799
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002800 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2801 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002802unlock:
2803 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002804 return err;
2805}
2806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002807static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002808 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002809 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002810{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002811 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002812 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002813 int err;
2814
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002815 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002816
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002817 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002818 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2819 MGMT_STATUS_NOT_POWERED, addr,
2820 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002821 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002822 }
2823
Johan Hedberg1707c602013-03-15 17:07:15 -05002824 if (addr->type == BDADDR_BREDR)
2825 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002826 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002827 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2828 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002829
Johan Hedberg272d90d2012-02-09 15:26:12 +02002830 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002831 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2832 MGMT_STATUS_NOT_CONNECTED, addr,
2833 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002834 goto done;
2835 }
2836
Johan Hedberg1707c602013-03-15 17:07:15 -05002837 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002838 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002839 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002840 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2841 MGMT_STATUS_SUCCESS, addr,
2842 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002843 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002844 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2845 MGMT_STATUS_FAILED, addr,
2846 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002847
Brian Gix47c15e22011-11-16 13:53:14 -08002848 goto done;
2849 }
2850
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002852 if (!cmd) {
2853 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002854 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002855 }
2856
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002857 cmd->cmd_complete = addr_cmd_complete;
2858
Brian Gix0df4c182011-11-16 13:53:13 -08002859 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002860 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2861 struct hci_cp_user_passkey_reply cp;
2862
Johan Hedberg1707c602013-03-15 17:07:15 -05002863 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002864 cp.passkey = passkey;
2865 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2866 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002867 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2868 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002869
Johan Hedberga664b5b2011-02-19 12:06:02 -03002870 if (err < 0)
2871 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002872
Brian Gix0df4c182011-11-16 13:53:13 -08002873done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002874 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002875 return err;
2876}
2877
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302878static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2879 void *data, u16 len)
2880{
2881 struct mgmt_cp_pin_code_neg_reply *cp = data;
2882
2883 BT_DBG("");
2884
Johan Hedberg1707c602013-03-15 17:07:15 -05002885 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302886 MGMT_OP_PIN_CODE_NEG_REPLY,
2887 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2888}
2889
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2891 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002892{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002893 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002894
2895 BT_DBG("");
2896
2897 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002898 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2899 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002900
Johan Hedberg1707c602013-03-15 17:07:15 -05002901 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 MGMT_OP_USER_CONFIRM_REPLY,
2903 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002904}
2905
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002906static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002908{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002909 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002910
2911 BT_DBG("");
2912
Johan Hedberg1707c602013-03-15 17:07:15 -05002913 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002914 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2915 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002916}
2917
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002918static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2919 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002921 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002922
2923 BT_DBG("");
2924
Johan Hedberg1707c602013-03-15 17:07:15 -05002925 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 MGMT_OP_USER_PASSKEY_REPLY,
2927 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002928}
2929
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002930static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002931 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002932{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002933 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002934
2935 BT_DBG("");
2936
Johan Hedberg1707c602013-03-15 17:07:15 -05002937 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2939 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002940}
2941
Marcel Holtmann1904a852015-01-11 13:50:44 -08002942static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05002943{
2944 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002945 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05002946
2947 BT_DBG("status 0x%02x", status);
2948
2949 hci_dev_lock(hdev);
2950
Johan Hedberg333ae952015-03-17 13:48:47 +02002951 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05002952 if (!cmd)
2953 goto unlock;
2954
2955 cp = cmd->param;
2956
2957 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002958 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2959 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05002960 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002961 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2962 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05002963
2964 mgmt_pending_remove(cmd);
2965
2966unlock:
2967 hci_dev_unlock(hdev);
2968}
2969
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002970static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002971 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002972{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002973 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002974 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002975 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002976 int err;
2977
2978 BT_DBG("");
2979
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002980 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002981
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002982 /* If the old values are the same as the new ones just return a
2983 * direct command complete event.
2984 */
2985 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2986 !memcmp(hdev->short_name, cp->short_name,
2987 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002988 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2989 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002990 goto failed;
2991 }
2992
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002993 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002994
Johan Hedbergb5235a62012-02-21 14:32:24 +02002995 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002996 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002997
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002998 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2999 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003000 if (err < 0)
3001 goto failed;
3002
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003003 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3004 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003005
Johan Hedbergb5235a62012-02-21 14:32:24 +02003006 goto failed;
3007 }
3008
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003009 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003010 if (!cmd) {
3011 err = -ENOMEM;
3012 goto failed;
3013 }
3014
Johan Hedberg13928972013-03-15 17:07:00 -05003015 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3016
Johan Hedberg890ea892013-03-15 17:06:52 -05003017 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003018
3019 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003020 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003021 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003022 }
3023
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003024 /* The name is stored in the scan response data and so
3025 * no need to udpate the advertising data here.
3026 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003027 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003028 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003029
Johan Hedberg13928972013-03-15 17:07:00 -05003030 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003031 if (err < 0)
3032 mgmt_pending_remove(cmd);
3033
3034failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003035 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003036 return err;
3037}
3038
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003039static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3040 u16 opcode, struct sk_buff *skb)
3041{
3042 struct mgmt_rp_read_local_oob_data mgmt_rp;
3043 size_t rp_size = sizeof(mgmt_rp);
3044 struct mgmt_pending_cmd *cmd;
3045
3046 BT_DBG("%s status %u", hdev->name, status);
3047
3048 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3049 if (!cmd)
3050 return;
3051
3052 if (status || !skb) {
3053 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3054 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3055 goto remove;
3056 }
3057
3058 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3059
3060 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3061 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3062
3063 if (skb->len < sizeof(*rp)) {
3064 mgmt_cmd_status(cmd->sk, hdev->id,
3065 MGMT_OP_READ_LOCAL_OOB_DATA,
3066 MGMT_STATUS_FAILED);
3067 goto remove;
3068 }
3069
3070 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3071 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3072
3073 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3074 } else {
3075 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3076
3077 if (skb->len < sizeof(*rp)) {
3078 mgmt_cmd_status(cmd->sk, hdev->id,
3079 MGMT_OP_READ_LOCAL_OOB_DATA,
3080 MGMT_STATUS_FAILED);
3081 goto remove;
3082 }
3083
3084 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3085 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3086
3087 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3088 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3089 }
3090
3091 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3092 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3093
3094remove:
3095 mgmt_pending_remove(cmd);
3096}
3097
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003098static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003100{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003101 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003102 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003103 int err;
3104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003105 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003106
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003107 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003108
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003109 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003110 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3111 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003112 goto unlock;
3113 }
3114
Andre Guedes9a1a1992012-07-24 15:03:48 -03003115 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003116 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3117 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003118 goto unlock;
3119 }
3120
Johan Hedberg333ae952015-03-17 13:48:47 +02003121 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003122 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3123 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003124 goto unlock;
3125 }
3126
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003127 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003128 if (!cmd) {
3129 err = -ENOMEM;
3130 goto unlock;
3131 }
3132
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003133 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003134
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003135 if (bredr_sc_enabled(hdev))
3136 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3137 else
3138 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3139
3140 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003141 if (err < 0)
3142 mgmt_pending_remove(cmd);
3143
3144unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003145 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003146 return err;
3147}
3148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003149static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003151{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003152 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003153 int err;
3154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003155 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003156
Johan Hedberg5d57e792015-01-23 10:10:38 +02003157 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003158 return mgmt_cmd_complete(sk, hdev->id,
3159 MGMT_OP_ADD_REMOTE_OOB_DATA,
3160 MGMT_STATUS_INVALID_PARAMS,
3161 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003163 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003164
Marcel Holtmannec109112014-01-10 02:07:30 -08003165 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3166 struct mgmt_cp_add_remote_oob_data *cp = data;
3167 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003168
Johan Hedbergc19a4952014-11-17 20:52:19 +02003169 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003170 err = mgmt_cmd_complete(sk, hdev->id,
3171 MGMT_OP_ADD_REMOTE_OOB_DATA,
3172 MGMT_STATUS_INVALID_PARAMS,
3173 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003174 goto unlock;
3175 }
3176
Marcel Holtmannec109112014-01-10 02:07:30 -08003177 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003178 cp->addr.type, cp->hash,
3179 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003180 if (err < 0)
3181 status = MGMT_STATUS_FAILED;
3182 else
3183 status = MGMT_STATUS_SUCCESS;
3184
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003185 err = mgmt_cmd_complete(sk, hdev->id,
3186 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3187 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003188 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3189 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003190 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003191 u8 status;
3192
Johan Hedberg86df9202014-10-26 20:52:27 +01003193 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003194 /* Enforce zero-valued 192-bit parameters as
3195 * long as legacy SMP OOB isn't implemented.
3196 */
3197 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3198 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003199 err = mgmt_cmd_complete(sk, hdev->id,
3200 MGMT_OP_ADD_REMOTE_OOB_DATA,
3201 MGMT_STATUS_INVALID_PARAMS,
3202 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003203 goto unlock;
3204 }
3205
Johan Hedberg86df9202014-10-26 20:52:27 +01003206 rand192 = NULL;
3207 hash192 = NULL;
3208 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003209 /* In case one of the P-192 values is set to zero,
3210 * then just disable OOB data for P-192.
3211 */
3212 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3213 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3214 rand192 = NULL;
3215 hash192 = NULL;
3216 } else {
3217 rand192 = cp->rand192;
3218 hash192 = cp->hash192;
3219 }
3220 }
3221
3222 /* In case one of the P-256 values is set to zero, then just
3223 * disable OOB data for P-256.
3224 */
3225 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3226 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3227 rand256 = NULL;
3228 hash256 = NULL;
3229 } else {
3230 rand256 = cp->rand256;
3231 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003232 }
3233
Johan Hedberg81328d52014-10-26 20:33:47 +01003234 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003235 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003236 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003237 if (err < 0)
3238 status = MGMT_STATUS_FAILED;
3239 else
3240 status = MGMT_STATUS_SUCCESS;
3241
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003242 err = mgmt_cmd_complete(sk, hdev->id,
3243 MGMT_OP_ADD_REMOTE_OOB_DATA,
3244 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003245 } else {
3246 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003247 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3248 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003249 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003250
Johan Hedbergc19a4952014-11-17 20:52:19 +02003251unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003252 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003253 return err;
3254}
3255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003256static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003257 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003258{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003259 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003260 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003261 int err;
3262
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003263 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003264
Johan Hedbergc19a4952014-11-17 20:52:19 +02003265 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003266 return mgmt_cmd_complete(sk, hdev->id,
3267 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3268 MGMT_STATUS_INVALID_PARAMS,
3269 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003271 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003272
Johan Hedbergeedbd582014-11-15 09:34:23 +02003273 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3274 hci_remote_oob_data_clear(hdev);
3275 status = MGMT_STATUS_SUCCESS;
3276 goto done;
3277 }
3278
Johan Hedberg6928a922014-10-26 20:46:09 +01003279 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003280 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003281 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003282 else
Szymon Janca6785be2012-12-13 15:11:21 +01003283 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003284
Johan Hedbergeedbd582014-11-15 09:34:23 +02003285done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3287 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003289 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003290 return err;
3291}
3292
Johan Hedberge68f0722015-11-11 08:30:30 +02003293void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003294{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003295 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003296
Andre Guedes7c307722013-04-30 15:29:28 -03003297 BT_DBG("status %d", status);
3298
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003299 hci_dev_lock(hdev);
3300
Johan Hedberg333ae952015-03-17 13:48:47 +02003301 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003302 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003303 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003304
Johan Hedberg78b781c2016-01-05 13:19:32 +02003305 if (!cmd)
3306 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3307
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003308 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003309 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003310 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003311 }
3312
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003313 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003314}
3315
Johan Hedberg591752a2015-11-11 08:11:24 +02003316static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3317 uint8_t *mgmt_status)
3318{
3319 switch (type) {
3320 case DISCOV_TYPE_LE:
3321 *mgmt_status = mgmt_le_support(hdev);
3322 if (*mgmt_status)
3323 return false;
3324 break;
3325 case DISCOV_TYPE_INTERLEAVED:
3326 *mgmt_status = mgmt_le_support(hdev);
3327 if (*mgmt_status)
3328 return false;
3329 /* Intentional fall-through */
3330 case DISCOV_TYPE_BREDR:
3331 *mgmt_status = mgmt_bredr_support(hdev);
3332 if (*mgmt_status)
3333 return false;
3334 break;
3335 default:
3336 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3337 return false;
3338 }
3339
3340 return true;
3341}
3342
Johan Hedberg78b781c2016-01-05 13:19:32 +02003343static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3344 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003345{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003346 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003347 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003348 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003349 int err;
3350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003351 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003352
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003353 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003354
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003355 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003356 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003357 MGMT_STATUS_NOT_POWERED,
3358 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003359 goto failed;
3360 }
3361
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003362 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003363 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003364 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3365 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003366 goto failed;
3367 }
3368
Johan Hedberg591752a2015-11-11 08:11:24 +02003369 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003370 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3371 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003372 goto failed;
3373 }
3374
Marcel Holtmann22078802014-12-05 11:45:22 +01003375 /* Clear the discovery filter first to free any previously
3376 * allocated memory for the UUID list.
3377 */
3378 hci_discovery_filter_clear(hdev);
3379
Andre Guedes4aab14e2012-02-17 20:39:36 -03003380 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003381 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003382 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3383 hdev->discovery.limited = true;
3384 else
3385 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003386
Johan Hedberg78b781c2016-01-05 13:19:32 +02003387 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003388 if (!cmd) {
3389 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003390 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003391 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003392
Johan Hedberge68f0722015-11-11 08:30:30 +02003393 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003394
3395 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003396 queue_work(hdev->req_workqueue, &hdev->discov_update);
3397 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003398
3399failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003400 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003401 return err;
3402}
3403
Johan Hedberg78b781c2016-01-05 13:19:32 +02003404static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3405 void *data, u16 len)
3406{
3407 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3408 data, len);
3409}
3410
3411static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3412 void *data, u16 len)
3413{
3414 return start_discovery_internal(sk, hdev,
3415 MGMT_OP_START_LIMITED_DISCOVERY,
3416 data, len);
3417}
3418
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003419static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3420 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003421{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003422 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3423 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003424}
3425
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003426static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3427 void *data, u16 len)
3428{
3429 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003430 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003431 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3432 u16 uuid_count, expected_len;
3433 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003434 int err;
3435
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003436 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003437
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003438 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003439
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003440 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003441 err = mgmt_cmd_complete(sk, hdev->id,
3442 MGMT_OP_START_SERVICE_DISCOVERY,
3443 MGMT_STATUS_NOT_POWERED,
3444 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003445 goto failed;
3446 }
3447
3448 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003449 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003450 err = mgmt_cmd_complete(sk, hdev->id,
3451 MGMT_OP_START_SERVICE_DISCOVERY,
3452 MGMT_STATUS_BUSY, &cp->type,
3453 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003454 goto failed;
3455 }
3456
3457 uuid_count = __le16_to_cpu(cp->uuid_count);
3458 if (uuid_count > max_uuid_count) {
3459 BT_ERR("service_discovery: too big uuid_count value %u",
3460 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003461 err = mgmt_cmd_complete(sk, hdev->id,
3462 MGMT_OP_START_SERVICE_DISCOVERY,
3463 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3464 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003465 goto failed;
3466 }
3467
3468 expected_len = sizeof(*cp) + uuid_count * 16;
3469 if (expected_len != len) {
3470 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3471 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003472 err = mgmt_cmd_complete(sk, hdev->id,
3473 MGMT_OP_START_SERVICE_DISCOVERY,
3474 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3475 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003476 goto failed;
3477 }
3478
Johan Hedberg591752a2015-11-11 08:11:24 +02003479 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3480 err = mgmt_cmd_complete(sk, hdev->id,
3481 MGMT_OP_START_SERVICE_DISCOVERY,
3482 status, &cp->type, sizeof(cp->type));
3483 goto failed;
3484 }
3485
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003486 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003487 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003488 if (!cmd) {
3489 err = -ENOMEM;
3490 goto failed;
3491 }
3492
Johan Hedberg2922a942014-12-05 13:36:06 +02003493 cmd->cmd_complete = service_discovery_cmd_complete;
3494
Marcel Holtmann22078802014-12-05 11:45:22 +01003495 /* Clear the discovery filter first to free any previously
3496 * allocated memory for the UUID list.
3497 */
3498 hci_discovery_filter_clear(hdev);
3499
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003500 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003501 hdev->discovery.type = cp->type;
3502 hdev->discovery.rssi = cp->rssi;
3503 hdev->discovery.uuid_count = uuid_count;
3504
3505 if (uuid_count > 0) {
3506 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3507 GFP_KERNEL);
3508 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003509 err = mgmt_cmd_complete(sk, hdev->id,
3510 MGMT_OP_START_SERVICE_DISCOVERY,
3511 MGMT_STATUS_FAILED,
3512 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003513 mgmt_pending_remove(cmd);
3514 goto failed;
3515 }
3516 }
3517
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003518 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003519 queue_work(hdev->req_workqueue, &hdev->discov_update);
3520 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003521
3522failed:
3523 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003524 return err;
3525}
3526
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003527void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003528{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003529 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003530
Andre Guedes0e05bba2013-04-30 15:29:33 -03003531 BT_DBG("status %d", status);
3532
3533 hci_dev_lock(hdev);
3534
Johan Hedberg333ae952015-03-17 13:48:47 +02003535 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003536 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003537 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003538 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003539 }
3540
Andre Guedes0e05bba2013-04-30 15:29:33 -03003541 hci_dev_unlock(hdev);
3542}
3543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003544static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003545 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003546{
Johan Hedbergd9306502012-02-20 23:25:18 +02003547 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003548 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003549 int err;
3550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003551 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003552
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003553 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003554
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003555 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003556 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3557 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3558 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003559 goto unlock;
3560 }
3561
3562 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003563 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3564 MGMT_STATUS_INVALID_PARAMS,
3565 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003566 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003567 }
3568
Johan Hedberg2922a942014-12-05 13:36:06 +02003569 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003570 if (!cmd) {
3571 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003572 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003573 }
3574
Johan Hedberg2922a942014-12-05 13:36:06 +02003575 cmd->cmd_complete = generic_cmd_complete;
3576
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003577 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3578 queue_work(hdev->req_workqueue, &hdev->discov_update);
3579 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003580
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003581unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003582 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003583 return err;
3584}
3585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003586static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003588{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003589 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003590 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003591 int err;
3592
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003593 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003594
Johan Hedberg561aafb2012-01-04 13:31:59 +02003595 hci_dev_lock(hdev);
3596
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003597 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003598 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3599 MGMT_STATUS_FAILED, &cp->addr,
3600 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003601 goto failed;
3602 }
3603
Johan Hedberga198e7b2012-02-17 14:27:06 +02003604 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003605 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003606 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3607 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3608 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003609 goto failed;
3610 }
3611
3612 if (cp->name_known) {
3613 e->name_state = NAME_KNOWN;
3614 list_del(&e->list);
3615 } else {
3616 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003617 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003618 }
3619
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003620 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3621 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003622
3623failed:
3624 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003625 return err;
3626}
3627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003628static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003629 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003630{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003631 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003632 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003633 int err;
3634
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003635 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003636
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003637 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003638 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3639 MGMT_STATUS_INVALID_PARAMS,
3640 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003641
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003642 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003643
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003644 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3645 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003646 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003647 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003648 goto done;
3649 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003650
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003651 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3652 sk);
3653 status = MGMT_STATUS_SUCCESS;
3654
3655done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003656 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3657 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003659 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003660
3661 return err;
3662}
3663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003664static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003665 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003666{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003667 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003668 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003669 int err;
3670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003671 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003672
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003673 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003674 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3675 MGMT_STATUS_INVALID_PARAMS,
3676 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003678 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003679
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003680 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3681 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003682 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003683 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003684 goto done;
3685 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003686
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003687 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3688 sk);
3689 status = MGMT_STATUS_SUCCESS;
3690
3691done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003692 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3693 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003694
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003695 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003696
3697 return err;
3698}
3699
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003700static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3701 u16 len)
3702{
3703 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003704 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003705 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003706 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003707
3708 BT_DBG("%s", hdev->name);
3709
Szymon Jancc72d4b82012-03-16 16:02:57 +01003710 source = __le16_to_cpu(cp->source);
3711
3712 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3714 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003715
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003716 hci_dev_lock(hdev);
3717
Szymon Jancc72d4b82012-03-16 16:02:57 +01003718 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003719 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3720 hdev->devid_product = __le16_to_cpu(cp->product);
3721 hdev->devid_version = __le16_to_cpu(cp->version);
3722
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003723 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3724 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003725
Johan Hedberg890ea892013-03-15 17:06:52 -05003726 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003727 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003728 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003729
3730 hci_dev_unlock(hdev);
3731
3732 return err;
3733}
3734
Arman Uguray24b4f382015-03-23 15:57:12 -07003735static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3736 u16 opcode)
3737{
3738 BT_DBG("status %d", status);
3739}
3740
Marcel Holtmann1904a852015-01-11 13:50:44 -08003741static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3742 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003743{
3744 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003745 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003746 u8 instance;
3747 struct adv_info *adv_instance;
3748 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003749
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303750 hci_dev_lock(hdev);
3751
Johan Hedberg4375f102013-09-25 13:26:10 +03003752 if (status) {
3753 u8 mgmt_err = mgmt_status(status);
3754
3755 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3756 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303757 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003758 }
3759
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003760 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003761 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003762 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003763 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003764
Johan Hedberg4375f102013-09-25 13:26:10 +03003765 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3766 &match);
3767
3768 new_settings(hdev, match.sk);
3769
3770 if (match.sk)
3771 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303772
Arman Uguray24b4f382015-03-23 15:57:12 -07003773 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003774 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003775 */
3776 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003777 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003778 goto unlock;
3779
Florian Grandel7816b822015-06-18 03:16:45 +02003780 instance = hdev->cur_adv_instance;
3781 if (!instance) {
3782 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3783 struct adv_info, list);
3784 if (!adv_instance)
3785 goto unlock;
3786
3787 instance = adv_instance->instance;
3788 }
3789
Arman Uguray24b4f382015-03-23 15:57:12 -07003790 hci_req_init(&req, hdev);
3791
Johan Hedbergf2252572015-11-18 12:49:20 +02003792 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003793
Florian Grandel7816b822015-06-18 03:16:45 +02003794 if (!err)
3795 err = hci_req_run(&req, enable_advertising_instance);
3796
3797 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003798 BT_ERR("Failed to re-configure advertising");
3799
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303800unlock:
3801 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003802}
3803
Marcel Holtmann21b51872013-10-10 09:47:53 -07003804static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3805 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003806{
3807 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003808 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003809 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003810 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003811 int err;
3812
3813 BT_DBG("request for %s", hdev->name);
3814
Johan Hedberge6fe7982013-10-02 15:45:22 +03003815 status = mgmt_le_support(hdev);
3816 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003817 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3818 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003819
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003820 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003821 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3822 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003823
3824 hci_dev_lock(hdev);
3825
3826 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003827
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003828 /* The following conditions are ones which mean that we should
3829 * not do any HCI communication but directly send a mgmt
3830 * response to user space (after toggling the flag if
3831 * necessary).
3832 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003833 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003834 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3835 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003836 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003837 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003838 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003839 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003840
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003841 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003842 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003843 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003844 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003845 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003846 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003847 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003848 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003849 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003850 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003851 }
3852
3853 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3854 if (err < 0)
3855 goto unlock;
3856
3857 if (changed)
3858 err = new_settings(hdev, sk);
3859
3860 goto unlock;
3861 }
3862
Johan Hedberg333ae952015-03-17 13:48:47 +02003863 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3864 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003865 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3866 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003867 goto unlock;
3868 }
3869
3870 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3871 if (!cmd) {
3872 err = -ENOMEM;
3873 goto unlock;
3874 }
3875
3876 hci_req_init(&req, hdev);
3877
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003878 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003879 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003880 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003881 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003882
Florian Grandel7816b822015-06-18 03:16:45 +02003883 cancel_adv_timeout(hdev);
3884
Arman Uguray24b4f382015-03-23 15:57:12 -07003885 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003886 /* Switch to instance "0" for the Set Advertising setting.
3887 * We cannot use update_[adv|scan_rsp]_data() here as the
3888 * HCI_ADVERTISING flag is not yet set.
3889 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02003890 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003891 __hci_req_update_adv_data(&req, 0x00);
3892 __hci_req_update_scan_rsp_data(&req, 0x00);
3893 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003894 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003895 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003896 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003897
3898 err = hci_req_run(&req, set_advertising_complete);
3899 if (err < 0)
3900 mgmt_pending_remove(cmd);
3901
3902unlock:
3903 hci_dev_unlock(hdev);
3904 return err;
3905}
3906
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003907static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3908 void *data, u16 len)
3909{
3910 struct mgmt_cp_set_static_address *cp = data;
3911 int err;
3912
3913 BT_DBG("%s", hdev->name);
3914
Marcel Holtmann62af4442013-10-02 22:10:32 -07003915 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003916 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3917 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003918
3919 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003920 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3921 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003922
3923 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3924 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003925 return mgmt_cmd_status(sk, hdev->id,
3926 MGMT_OP_SET_STATIC_ADDRESS,
3927 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003928
3929 /* Two most significant bits shall be set */
3930 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003931 return mgmt_cmd_status(sk, hdev->id,
3932 MGMT_OP_SET_STATIC_ADDRESS,
3933 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003934 }
3935
3936 hci_dev_lock(hdev);
3937
3938 bacpy(&hdev->static_addr, &cp->bdaddr);
3939
Marcel Holtmann93690c22015-03-06 10:11:21 -08003940 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3941 if (err < 0)
3942 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003943
Marcel Holtmann93690c22015-03-06 10:11:21 -08003944 err = new_settings(hdev, sk);
3945
3946unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003947 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003948 return err;
3949}
3950
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003951static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3952 void *data, u16 len)
3953{
3954 struct mgmt_cp_set_scan_params *cp = data;
3955 __u16 interval, window;
3956 int err;
3957
3958 BT_DBG("%s", hdev->name);
3959
3960 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003961 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3962 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003963
3964 interval = __le16_to_cpu(cp->interval);
3965
3966 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003967 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3968 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003969
3970 window = __le16_to_cpu(cp->window);
3971
3972 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003973 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3974 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003975
Marcel Holtmann899e1072013-10-14 09:55:32 -07003976 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02003977 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3978 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07003979
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003980 hci_dev_lock(hdev);
3981
3982 hdev->le_scan_interval = interval;
3983 hdev->le_scan_window = window;
3984
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003985 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
3986 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003987
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003988 /* If background scan is running, restart it so new parameters are
3989 * loaded.
3990 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003991 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003992 hdev->discovery.state == DISCOVERY_STOPPED) {
3993 struct hci_request req;
3994
3995 hci_req_init(&req, hdev);
3996
3997 hci_req_add_le_scan_disable(&req);
3998 hci_req_add_le_passive_scan(&req);
3999
4000 hci_req_run(&req, NULL);
4001 }
4002
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004003 hci_dev_unlock(hdev);
4004
4005 return err;
4006}
4007
Marcel Holtmann1904a852015-01-11 13:50:44 -08004008static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4009 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004010{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004011 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004012
4013 BT_DBG("status 0x%02x", status);
4014
4015 hci_dev_lock(hdev);
4016
Johan Hedberg333ae952015-03-17 13:48:47 +02004017 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004018 if (!cmd)
4019 goto unlock;
4020
4021 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004022 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4023 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004024 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004025 struct mgmt_mode *cp = cmd->param;
4026
4027 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004028 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004029 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004030 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004031
Johan Hedberg33e38b32013-03-15 17:07:05 -05004032 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4033 new_settings(hdev, cmd->sk);
4034 }
4035
4036 mgmt_pending_remove(cmd);
4037
4038unlock:
4039 hci_dev_unlock(hdev);
4040}
4041
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004042static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004043 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004044{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004045 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004046 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004047 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004048 int err;
4049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004050 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004051
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004052 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004053 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004054 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4055 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004056
Johan Hedberga7e80f22013-01-09 16:05:19 +02004057 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004058 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4059 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004060
Antti Julkuf6422ec2011-06-22 13:11:56 +03004061 hci_dev_lock(hdev);
4062
Johan Hedberg333ae952015-03-17 13:48:47 +02004063 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004064 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4065 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004066 goto unlock;
4067 }
4068
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004069 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004070 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4071 hdev);
4072 goto unlock;
4073 }
4074
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004075 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004076 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004077 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4078 hdev);
4079 new_settings(hdev, sk);
4080 goto unlock;
4081 }
4082
Johan Hedberg33e38b32013-03-15 17:07:05 -05004083 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4084 data, len);
4085 if (!cmd) {
4086 err = -ENOMEM;
4087 goto unlock;
4088 }
4089
4090 hci_req_init(&req, hdev);
4091
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004092 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004093
4094 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004095 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004096 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4097 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004098 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004099 }
4100
Johan Hedberg33e38b32013-03-15 17:07:05 -05004101unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004102 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004103
Antti Julkuf6422ec2011-06-22 13:11:56 +03004104 return err;
4105}
4106
Marcel Holtmann1904a852015-01-11 13:50:44 -08004107static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004108{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004109 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004110
4111 BT_DBG("status 0x%02x", status);
4112
4113 hci_dev_lock(hdev);
4114
Johan Hedberg333ae952015-03-17 13:48:47 +02004115 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004116 if (!cmd)
4117 goto unlock;
4118
4119 if (status) {
4120 u8 mgmt_err = mgmt_status(status);
4121
4122 /* We need to restore the flag if related HCI commands
4123 * failed.
4124 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004125 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004126
Johan Hedberga69e8372015-03-06 21:08:53 +02004127 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004128 } else {
4129 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4130 new_settings(hdev, cmd->sk);
4131 }
4132
4133 mgmt_pending_remove(cmd);
4134
4135unlock:
4136 hci_dev_unlock(hdev);
4137}
4138
4139static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4140{
4141 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004142 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004143 struct hci_request req;
4144 int err;
4145
4146 BT_DBG("request for %s", hdev->name);
4147
4148 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004149 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4150 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004151
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004152 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4154 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004155
4156 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004157 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4158 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004159
4160 hci_dev_lock(hdev);
4161
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004162 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004163 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4164 goto unlock;
4165 }
4166
4167 if (!hdev_is_powered(hdev)) {
4168 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004169 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4170 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4171 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4172 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4173 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004174 }
4175
Marcel Holtmannce05d602015-03-13 02:11:03 -07004176 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004177
4178 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4179 if (err < 0)
4180 goto unlock;
4181
4182 err = new_settings(hdev, sk);
4183 goto unlock;
4184 }
4185
4186 /* Reject disabling when powered on */
4187 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004188 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4189 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004190 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004191 } else {
4192 /* When configuring a dual-mode controller to operate
4193 * with LE only and using a static address, then switching
4194 * BR/EDR back on is not allowed.
4195 *
4196 * Dual-mode controllers shall operate with the public
4197 * address as its identity address for BR/EDR and LE. So
4198 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004199 *
4200 * The same restrictions applies when secure connections
4201 * has been enabled. For BR/EDR this is a controller feature
4202 * while for LE it is a host stack feature. This means that
4203 * switching BR/EDR back on when secure connections has been
4204 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004205 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004206 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004207 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004208 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004209 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4210 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004211 goto unlock;
4212 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004213 }
4214
Johan Hedberg333ae952015-03-17 13:48:47 +02004215 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004216 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4217 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004218 goto unlock;
4219 }
4220
4221 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4222 if (!cmd) {
4223 err = -ENOMEM;
4224 goto unlock;
4225 }
4226
Johan Hedbergf2252572015-11-18 12:49:20 +02004227 /* We need to flip the bit already here so that
4228 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004229 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004230 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004231
4232 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004233
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004234 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004235 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004236
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004237 /* Since only the advertising data flags will change, there
4238 * is no need to update the scan response data.
4239 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004240 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004241
Johan Hedberg0663ca22013-10-02 13:43:14 +03004242 err = hci_req_run(&req, set_bredr_complete);
4243 if (err < 0)
4244 mgmt_pending_remove(cmd);
4245
4246unlock:
4247 hci_dev_unlock(hdev);
4248 return err;
4249}
4250
Johan Hedberga1443f52015-01-23 15:42:46 +02004251static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4252{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004253 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004254 struct mgmt_mode *cp;
4255
4256 BT_DBG("%s status %u", hdev->name, status);
4257
4258 hci_dev_lock(hdev);
4259
Johan Hedberg333ae952015-03-17 13:48:47 +02004260 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004261 if (!cmd)
4262 goto unlock;
4263
4264 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004265 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4266 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004267 goto remove;
4268 }
4269
4270 cp = cmd->param;
4271
4272 switch (cp->val) {
4273 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004274 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4275 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004276 break;
4277 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004278 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004279 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004280 break;
4281 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004282 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4283 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004284 break;
4285 }
4286
4287 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4288 new_settings(hdev, cmd->sk);
4289
4290remove:
4291 mgmt_pending_remove(cmd);
4292unlock:
4293 hci_dev_unlock(hdev);
4294}
4295
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004296static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4297 void *data, u16 len)
4298{
4299 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004300 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004301 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004302 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004303 int err;
4304
4305 BT_DBG("request for %s", hdev->name);
4306
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004307 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004308 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4310 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004311
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004312 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004313 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004314 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004315 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4316 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004317
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004318 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004319 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004320 MGMT_STATUS_INVALID_PARAMS);
4321
4322 hci_dev_lock(hdev);
4323
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004324 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004325 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004326 bool changed;
4327
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004328 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004329 changed = !hci_dev_test_and_set_flag(hdev,
4330 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004331 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004332 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004333 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004334 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004335 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004336 changed = hci_dev_test_and_clear_flag(hdev,
4337 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004338 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004339 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004340
4341 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4342 if (err < 0)
4343 goto failed;
4344
4345 if (changed)
4346 err = new_settings(hdev, sk);
4347
4348 goto failed;
4349 }
4350
Johan Hedberg333ae952015-03-17 13:48:47 +02004351 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004352 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4353 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004354 goto failed;
4355 }
4356
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004357 val = !!cp->val;
4358
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004359 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4360 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004361 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4362 goto failed;
4363 }
4364
4365 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4366 if (!cmd) {
4367 err = -ENOMEM;
4368 goto failed;
4369 }
4370
Johan Hedberga1443f52015-01-23 15:42:46 +02004371 hci_req_init(&req, hdev);
4372 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4373 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004374 if (err < 0) {
4375 mgmt_pending_remove(cmd);
4376 goto failed;
4377 }
4378
4379failed:
4380 hci_dev_unlock(hdev);
4381 return err;
4382}
4383
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004384static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4385 void *data, u16 len)
4386{
4387 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004388 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004389 int err;
4390
4391 BT_DBG("request for %s", hdev->name);
4392
Johan Hedbergb97109792014-06-24 14:00:28 +03004393 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004394 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4395 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004396
4397 hci_dev_lock(hdev);
4398
4399 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004400 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004401 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004402 changed = hci_dev_test_and_clear_flag(hdev,
4403 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004404
Johan Hedbergb97109792014-06-24 14:00:28 +03004405 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004406 use_changed = !hci_dev_test_and_set_flag(hdev,
4407 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004408 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004409 use_changed = hci_dev_test_and_clear_flag(hdev,
4410 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004411
4412 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004413 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004414 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4415 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4416 sizeof(mode), &mode);
4417 }
4418
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004419 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4420 if (err < 0)
4421 goto unlock;
4422
4423 if (changed)
4424 err = new_settings(hdev, sk);
4425
4426unlock:
4427 hci_dev_unlock(hdev);
4428 return err;
4429}
4430
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004431static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4432 u16 len)
4433{
4434 struct mgmt_cp_set_privacy *cp = cp_data;
4435 bool changed;
4436 int err;
4437
4438 BT_DBG("request for %s", hdev->name);
4439
4440 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004441 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4442 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004443
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004444 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004445 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4446 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004447
4448 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004449 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4450 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004451
4452 hci_dev_lock(hdev);
4453
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004454 /* If user space supports this command it is also expected to
4455 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4456 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004457 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004458
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004459 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004460 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004461 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004462 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004463 if (cp->privacy == 0x02)
4464 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4465 else
4466 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004467 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004468 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004469 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004470 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004471 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004472 }
4473
4474 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4475 if (err < 0)
4476 goto unlock;
4477
4478 if (changed)
4479 err = new_settings(hdev, sk);
4480
4481unlock:
4482 hci_dev_unlock(hdev);
4483 return err;
4484}
4485
Johan Hedberg41edf162014-02-18 10:19:35 +02004486static bool irk_is_valid(struct mgmt_irk_info *irk)
4487{
4488 switch (irk->addr.type) {
4489 case BDADDR_LE_PUBLIC:
4490 return true;
4491
4492 case BDADDR_LE_RANDOM:
4493 /* Two most significant bits shall be set */
4494 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4495 return false;
4496 return true;
4497 }
4498
4499 return false;
4500}
4501
4502static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4503 u16 len)
4504{
4505 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004506 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4507 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004508 u16 irk_count, expected_len;
4509 int i, err;
4510
4511 BT_DBG("request for %s", hdev->name);
4512
4513 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004514 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4515 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004516
4517 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004518 if (irk_count > max_irk_count) {
4519 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004520 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4521 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004522 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004523
4524 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4525 if (expected_len != len) {
4526 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004527 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004528 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4529 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004530 }
4531
4532 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4533
4534 for (i = 0; i < irk_count; i++) {
4535 struct mgmt_irk_info *key = &cp->irks[i];
4536
4537 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004538 return mgmt_cmd_status(sk, hdev->id,
4539 MGMT_OP_LOAD_IRKS,
4540 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004541 }
4542
4543 hci_dev_lock(hdev);
4544
4545 hci_smp_irks_clear(hdev);
4546
4547 for (i = 0; i < irk_count; i++) {
4548 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004549
Johan Hedberg85813a72015-10-21 18:02:59 +03004550 hci_add_irk(hdev, &irk->addr.bdaddr,
4551 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004552 BDADDR_ANY);
4553 }
4554
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004555 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004556
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004557 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004558
4559 hci_dev_unlock(hdev);
4560
4561 return err;
4562}
4563
Johan Hedberg3f706b72013-01-20 14:27:16 +02004564static bool ltk_is_valid(struct mgmt_ltk_info *key)
4565{
4566 if (key->master != 0x00 && key->master != 0x01)
4567 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004568
4569 switch (key->addr.type) {
4570 case BDADDR_LE_PUBLIC:
4571 return true;
4572
4573 case BDADDR_LE_RANDOM:
4574 /* Two most significant bits shall be set */
4575 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4576 return false;
4577 return true;
4578 }
4579
4580 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004581}
4582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004583static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004585{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004586 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004587 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4588 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004589 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004590 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004591
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004592 BT_DBG("request for %s", hdev->name);
4593
4594 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004595 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4596 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004597
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004598 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004599 if (key_count > max_key_count) {
4600 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004601 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4602 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004603 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004604
4605 expected_len = sizeof(*cp) + key_count *
4606 sizeof(struct mgmt_ltk_info);
4607 if (expected_len != len) {
4608 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004609 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004610 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4611 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004612 }
4613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004614 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004615
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004616 for (i = 0; i < key_count; i++) {
4617 struct mgmt_ltk_info *key = &cp->keys[i];
4618
Johan Hedberg3f706b72013-01-20 14:27:16 +02004619 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004620 return mgmt_cmd_status(sk, hdev->id,
4621 MGMT_OP_LOAD_LONG_TERM_KEYS,
4622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004623 }
4624
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004625 hci_dev_lock(hdev);
4626
4627 hci_smp_ltks_clear(hdev);
4628
4629 for (i = 0; i < key_count; i++) {
4630 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004631 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004632
Johan Hedberg61b43352014-05-29 19:36:53 +03004633 switch (key->type) {
4634 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004635 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004636 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004637 break;
4638 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004639 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004640 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004641 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004642 case MGMT_LTK_P256_UNAUTH:
4643 authenticated = 0x00;
4644 type = SMP_LTK_P256;
4645 break;
4646 case MGMT_LTK_P256_AUTH:
4647 authenticated = 0x01;
4648 type = SMP_LTK_P256;
4649 break;
4650 case MGMT_LTK_P256_DEBUG:
4651 authenticated = 0x00;
4652 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004653 default:
4654 continue;
4655 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004656
Johan Hedberg85813a72015-10-21 18:02:59 +03004657 hci_add_ltk(hdev, &key->addr.bdaddr,
4658 le_addr_type(key->addr.type), type, authenticated,
4659 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004660 }
4661
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004662 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004663 NULL, 0);
4664
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004665 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004666
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004667 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004668}
4669
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004670static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004671{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004672 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004673 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004674 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004675
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004676 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004677
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004678 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004679 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004680 rp.tx_power = conn->tx_power;
4681 rp.max_tx_power = conn->max_tx_power;
4682 } else {
4683 rp.rssi = HCI_RSSI_INVALID;
4684 rp.tx_power = HCI_TX_POWER_INVALID;
4685 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004686 }
4687
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004688 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4689 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004690
4691 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004692 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004693
4694 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004695}
4696
Marcel Holtmann1904a852015-01-11 13:50:44 -08004697static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4698 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004699{
4700 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004701 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004702 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004703 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004704 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004705
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004706 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004707
4708 hci_dev_lock(hdev);
4709
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004710 /* Commands sent in request are either Read RSSI or Read Transmit Power
4711 * Level so we check which one was last sent to retrieve connection
4712 * handle. Both commands have handle as first parameter so it's safe to
4713 * cast data on the same command struct.
4714 *
4715 * First command sent is always Read RSSI and we fail only if it fails.
4716 * In other case we simply override error to indicate success as we
4717 * already remembered if TX power value is actually valid.
4718 */
4719 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4720 if (!cp) {
4721 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004722 status = MGMT_STATUS_SUCCESS;
4723 } else {
4724 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004725 }
4726
4727 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004728 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004729 goto unlock;
4730 }
4731
4732 handle = __le16_to_cpu(cp->handle);
4733 conn = hci_conn_hash_lookup_handle(hdev, handle);
4734 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004735 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004736 goto unlock;
4737 }
4738
Johan Hedberg333ae952015-03-17 13:48:47 +02004739 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004740 if (!cmd)
4741 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004742
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004743 cmd->cmd_complete(cmd, status);
4744 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004745
4746unlock:
4747 hci_dev_unlock(hdev);
4748}
4749
4750static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4751 u16 len)
4752{
4753 struct mgmt_cp_get_conn_info *cp = data;
4754 struct mgmt_rp_get_conn_info rp;
4755 struct hci_conn *conn;
4756 unsigned long conn_info_age;
4757 int err = 0;
4758
4759 BT_DBG("%s", hdev->name);
4760
4761 memset(&rp, 0, sizeof(rp));
4762 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4763 rp.addr.type = cp->addr.type;
4764
4765 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004766 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4767 MGMT_STATUS_INVALID_PARAMS,
4768 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004769
4770 hci_dev_lock(hdev);
4771
4772 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004773 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4774 MGMT_STATUS_NOT_POWERED, &rp,
4775 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004776 goto unlock;
4777 }
4778
4779 if (cp->addr.type == BDADDR_BREDR)
4780 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4781 &cp->addr.bdaddr);
4782 else
4783 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4784
4785 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004786 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4787 MGMT_STATUS_NOT_CONNECTED, &rp,
4788 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004789 goto unlock;
4790 }
4791
Johan Hedberg333ae952015-03-17 13:48:47 +02004792 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004793 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4794 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004795 goto unlock;
4796 }
4797
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004798 /* To avoid client trying to guess when to poll again for information we
4799 * calculate conn info age as random value between min/max set in hdev.
4800 */
4801 conn_info_age = hdev->conn_info_min_age +
4802 prandom_u32_max(hdev->conn_info_max_age -
4803 hdev->conn_info_min_age);
4804
4805 /* Query controller to refresh cached values if they are too old or were
4806 * never read.
4807 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004808 if (time_after(jiffies, conn->conn_info_timestamp +
4809 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004810 !conn->conn_info_timestamp) {
4811 struct hci_request req;
4812 struct hci_cp_read_tx_power req_txp_cp;
4813 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004814 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004815
4816 hci_req_init(&req, hdev);
4817 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4818 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4819 &req_rssi_cp);
4820
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004821 /* For LE links TX power does not change thus we don't need to
4822 * query for it once value is known.
4823 */
4824 if (!bdaddr_type_is_le(cp->addr.type) ||
4825 conn->tx_power == HCI_TX_POWER_INVALID) {
4826 req_txp_cp.handle = cpu_to_le16(conn->handle);
4827 req_txp_cp.type = 0x00;
4828 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4829 sizeof(req_txp_cp), &req_txp_cp);
4830 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004831
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004832 /* Max TX power needs to be read only once per connection */
4833 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4834 req_txp_cp.handle = cpu_to_le16(conn->handle);
4835 req_txp_cp.type = 0x01;
4836 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4837 sizeof(req_txp_cp), &req_txp_cp);
4838 }
4839
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004840 err = hci_req_run(&req, conn_info_refresh_complete);
4841 if (err < 0)
4842 goto unlock;
4843
4844 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4845 data, len);
4846 if (!cmd) {
4847 err = -ENOMEM;
4848 goto unlock;
4849 }
4850
4851 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004852 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004853 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004854
4855 conn->conn_info_timestamp = jiffies;
4856 } else {
4857 /* Cache is valid, just reply with values cached in hci_conn */
4858 rp.rssi = conn->rssi;
4859 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004860 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004861
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004862 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4863 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004864 }
4865
4866unlock:
4867 hci_dev_unlock(hdev);
4868 return err;
4869}
4870
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004871static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004872{
4873 struct hci_conn *conn = cmd->user_data;
4874 struct mgmt_rp_get_clock_info rp;
4875 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004876 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004877
4878 memset(&rp, 0, sizeof(rp));
4879 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
4880
4881 if (status)
4882 goto complete;
4883
4884 hdev = hci_dev_get(cmd->index);
4885 if (hdev) {
4886 rp.local_clock = cpu_to_le32(hdev->clock);
4887 hci_dev_put(hdev);
4888 }
4889
4890 if (conn) {
4891 rp.piconet_clock = cpu_to_le32(conn->clock);
4892 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4893 }
4894
4895complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004896 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4897 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004898
4899 if (conn) {
4900 hci_conn_drop(conn);
4901 hci_conn_put(conn);
4902 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004903
4904 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004905}
4906
Marcel Holtmann1904a852015-01-11 13:50:44 -08004907static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004908{
Johan Hedberg95868422014-06-28 17:54:07 +03004909 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004910 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004911 struct hci_conn *conn;
4912
4913 BT_DBG("%s status %u", hdev->name, status);
4914
4915 hci_dev_lock(hdev);
4916
4917 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4918 if (!hci_cp)
4919 goto unlock;
4920
4921 if (hci_cp->which) {
4922 u16 handle = __le16_to_cpu(hci_cp->handle);
4923 conn = hci_conn_hash_lookup_handle(hdev, handle);
4924 } else {
4925 conn = NULL;
4926 }
4927
Johan Hedberg333ae952015-03-17 13:48:47 +02004928 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004929 if (!cmd)
4930 goto unlock;
4931
Johan Hedberg69487372014-12-05 13:36:07 +02004932 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004933 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004934
4935unlock:
4936 hci_dev_unlock(hdev);
4937}
4938
4939static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4940 u16 len)
4941{
4942 struct mgmt_cp_get_clock_info *cp = data;
4943 struct mgmt_rp_get_clock_info rp;
4944 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004945 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004946 struct hci_request req;
4947 struct hci_conn *conn;
4948 int err;
4949
4950 BT_DBG("%s", hdev->name);
4951
4952 memset(&rp, 0, sizeof(rp));
4953 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4954 rp.addr.type = cp->addr.type;
4955
4956 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004957 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4958 MGMT_STATUS_INVALID_PARAMS,
4959 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004960
4961 hci_dev_lock(hdev);
4962
4963 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004964 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4965 MGMT_STATUS_NOT_POWERED, &rp,
4966 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004967 goto unlock;
4968 }
4969
4970 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4971 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4972 &cp->addr.bdaddr);
4973 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004974 err = mgmt_cmd_complete(sk, hdev->id,
4975 MGMT_OP_GET_CLOCK_INFO,
4976 MGMT_STATUS_NOT_CONNECTED,
4977 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004978 goto unlock;
4979 }
4980 } else {
4981 conn = NULL;
4982 }
4983
4984 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
4985 if (!cmd) {
4986 err = -ENOMEM;
4987 goto unlock;
4988 }
4989
Johan Hedberg69487372014-12-05 13:36:07 +02004990 cmd->cmd_complete = clock_info_cmd_complete;
4991
Johan Hedberg95868422014-06-28 17:54:07 +03004992 hci_req_init(&req, hdev);
4993
4994 memset(&hci_cp, 0, sizeof(hci_cp));
4995 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4996
4997 if (conn) {
4998 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004999 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005000
5001 hci_cp.handle = cpu_to_le16(conn->handle);
5002 hci_cp.which = 0x01; /* Piconet clock */
5003 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5004 }
5005
5006 err = hci_req_run(&req, get_clock_info_complete);
5007 if (err < 0)
5008 mgmt_pending_remove(cmd);
5009
5010unlock:
5011 hci_dev_unlock(hdev);
5012 return err;
5013}
5014
Johan Hedberg5a154e62014-12-19 22:26:02 +02005015static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5016{
5017 struct hci_conn *conn;
5018
5019 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5020 if (!conn)
5021 return false;
5022
5023 if (conn->dst_type != type)
5024 return false;
5025
5026 if (conn->state != BT_CONNECTED)
5027 return false;
5028
5029 return true;
5030}
5031
5032/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005033static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005034 u8 addr_type, u8 auto_connect)
5035{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005036 struct hci_conn_params *params;
5037
5038 params = hci_conn_params_add(hdev, addr, addr_type);
5039 if (!params)
5040 return -EIO;
5041
5042 if (params->auto_connect == auto_connect)
5043 return 0;
5044
5045 list_del_init(&params->action);
5046
5047 switch (auto_connect) {
5048 case HCI_AUTO_CONN_DISABLED:
5049 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005050 /* If auto connect is being disabled when we're trying to
5051 * connect to device, keep connecting.
5052 */
5053 if (params->explicit_connect)
5054 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005055 break;
5056 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005057 if (params->explicit_connect)
5058 list_add(&params->action, &hdev->pend_le_conns);
5059 else
5060 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005061 break;
5062 case HCI_AUTO_CONN_DIRECT:
5063 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005064 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005065 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005066 break;
5067 }
5068
5069 params->auto_connect = auto_connect;
5070
5071 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5072 auto_connect);
5073
5074 return 0;
5075}
5076
Marcel Holtmann8afef092014-06-29 22:28:34 +02005077static void device_added(struct sock *sk, struct hci_dev *hdev,
5078 bdaddr_t *bdaddr, u8 type, u8 action)
5079{
5080 struct mgmt_ev_device_added ev;
5081
5082 bacpy(&ev.addr.bdaddr, bdaddr);
5083 ev.addr.type = type;
5084 ev.action = action;
5085
5086 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5087}
5088
Marcel Holtmann2faade52014-06-29 19:44:03 +02005089static int add_device(struct sock *sk, struct hci_dev *hdev,
5090 void *data, u16 len)
5091{
5092 struct mgmt_cp_add_device *cp = data;
5093 u8 auto_conn, addr_type;
5094 int err;
5095
5096 BT_DBG("%s", hdev->name);
5097
Johan Hedberg66593582014-07-09 12:59:14 +03005098 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005099 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005100 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5101 MGMT_STATUS_INVALID_PARAMS,
5102 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005103
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005104 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005105 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5106 MGMT_STATUS_INVALID_PARAMS,
5107 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005108
5109 hci_dev_lock(hdev);
5110
Johan Hedberg66593582014-07-09 12:59:14 +03005111 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005112 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005113 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005114 err = mgmt_cmd_complete(sk, hdev->id,
5115 MGMT_OP_ADD_DEVICE,
5116 MGMT_STATUS_INVALID_PARAMS,
5117 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005118 goto unlock;
5119 }
5120
5121 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5122 cp->addr.type);
5123 if (err)
5124 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005125
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005126 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005127
Johan Hedberg66593582014-07-09 12:59:14 +03005128 goto added;
5129 }
5130
Johan Hedberg85813a72015-10-21 18:02:59 +03005131 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005132
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005133 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005134 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005135 else if (cp->action == 0x01)
5136 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005137 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005138 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005139
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005140 /* Kernel internally uses conn_params with resolvable private
5141 * address, but Add Device allows only identity addresses.
5142 * Make sure it is enforced before calling
5143 * hci_conn_params_lookup.
5144 */
5145 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005146 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5147 MGMT_STATUS_INVALID_PARAMS,
5148 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005149 goto unlock;
5150 }
5151
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005152 /* If the connection parameters don't exist for this device,
5153 * they will be created and configured with defaults.
5154 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005155 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005156 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005157 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5158 MGMT_STATUS_FAILED, &cp->addr,
5159 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005160 goto unlock;
5161 }
5162
Johan Hedberg51d7a942015-11-11 08:11:18 +02005163 hci_update_background_scan(hdev);
5164
Johan Hedberg66593582014-07-09 12:59:14 +03005165added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005166 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5167
Johan Hedberg51d7a942015-11-11 08:11:18 +02005168 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5169 MGMT_STATUS_SUCCESS, &cp->addr,
5170 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005171
5172unlock:
5173 hci_dev_unlock(hdev);
5174 return err;
5175}
5176
Marcel Holtmann8afef092014-06-29 22:28:34 +02005177static void device_removed(struct sock *sk, struct hci_dev *hdev,
5178 bdaddr_t *bdaddr, u8 type)
5179{
5180 struct mgmt_ev_device_removed ev;
5181
5182 bacpy(&ev.addr.bdaddr, bdaddr);
5183 ev.addr.type = type;
5184
5185 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5186}
5187
Marcel Holtmann2faade52014-06-29 19:44:03 +02005188static int remove_device(struct sock *sk, struct hci_dev *hdev,
5189 void *data, u16 len)
5190{
5191 struct mgmt_cp_remove_device *cp = data;
5192 int err;
5193
5194 BT_DBG("%s", hdev->name);
5195
5196 hci_dev_lock(hdev);
5197
5198 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005199 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005200 u8 addr_type;
5201
Johan Hedberg66593582014-07-09 12:59:14 +03005202 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005203 err = mgmt_cmd_complete(sk, hdev->id,
5204 MGMT_OP_REMOVE_DEVICE,
5205 MGMT_STATUS_INVALID_PARAMS,
5206 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005207 goto unlock;
5208 }
5209
Johan Hedberg66593582014-07-09 12:59:14 +03005210 if (cp->addr.type == BDADDR_BREDR) {
5211 err = hci_bdaddr_list_del(&hdev->whitelist,
5212 &cp->addr.bdaddr,
5213 cp->addr.type);
5214 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005215 err = mgmt_cmd_complete(sk, hdev->id,
5216 MGMT_OP_REMOVE_DEVICE,
5217 MGMT_STATUS_INVALID_PARAMS,
5218 &cp->addr,
5219 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005220 goto unlock;
5221 }
5222
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005223 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005224
Johan Hedberg66593582014-07-09 12:59:14 +03005225 device_removed(sk, hdev, &cp->addr.bdaddr,
5226 cp->addr.type);
5227 goto complete;
5228 }
5229
Johan Hedberg85813a72015-10-21 18:02:59 +03005230 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005231
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005232 /* Kernel internally uses conn_params with resolvable private
5233 * address, but Remove Device allows only identity addresses.
5234 * Make sure it is enforced before calling
5235 * hci_conn_params_lookup.
5236 */
5237 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005238 err = mgmt_cmd_complete(sk, hdev->id,
5239 MGMT_OP_REMOVE_DEVICE,
5240 MGMT_STATUS_INVALID_PARAMS,
5241 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005242 goto unlock;
5243 }
5244
Johan Hedbergc71593d2014-07-02 17:37:28 +03005245 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5246 addr_type);
5247 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005248 err = mgmt_cmd_complete(sk, hdev->id,
5249 MGMT_OP_REMOVE_DEVICE,
5250 MGMT_STATUS_INVALID_PARAMS,
5251 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005252 goto unlock;
5253 }
5254
Johan Hedberg679d2b62015-10-16 10:07:52 +03005255 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5256 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005257 err = mgmt_cmd_complete(sk, hdev->id,
5258 MGMT_OP_REMOVE_DEVICE,
5259 MGMT_STATUS_INVALID_PARAMS,
5260 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005261 goto unlock;
5262 }
5263
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005264 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005265 list_del(&params->list);
5266 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005267 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005268
5269 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005270 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005271 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005272 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005273
Marcel Holtmann2faade52014-06-29 19:44:03 +02005274 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005275 err = mgmt_cmd_complete(sk, hdev->id,
5276 MGMT_OP_REMOVE_DEVICE,
5277 MGMT_STATUS_INVALID_PARAMS,
5278 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005279 goto unlock;
5280 }
5281
Johan Hedberg66593582014-07-09 12:59:14 +03005282 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5283 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5284 list_del(&b->list);
5285 kfree(b);
5286 }
5287
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005288 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005289
Johan Hedberg19de0822014-07-06 13:06:51 +03005290 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5291 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5292 continue;
5293 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005294 if (p->explicit_connect) {
5295 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5296 continue;
5297 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005298 list_del(&p->action);
5299 list_del(&p->list);
5300 kfree(p);
5301 }
5302
5303 BT_DBG("All LE connection parameters were removed");
5304
Johan Hedberg51d7a942015-11-11 08:11:18 +02005305 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005306 }
5307
Johan Hedberg66593582014-07-09 12:59:14 +03005308complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005309 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5310 MGMT_STATUS_SUCCESS, &cp->addr,
5311 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005312unlock:
5313 hci_dev_unlock(hdev);
5314 return err;
5315}
5316
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005317static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5318 u16 len)
5319{
5320 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005321 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5322 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005323 u16 param_count, expected_len;
5324 int i;
5325
5326 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005327 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5328 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005329
5330 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005331 if (param_count > max_param_count) {
5332 BT_ERR("load_conn_param: too big param_count value %u",
5333 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005334 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5335 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005336 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005337
5338 expected_len = sizeof(*cp) + param_count *
5339 sizeof(struct mgmt_conn_param);
5340 if (expected_len != len) {
5341 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5342 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005343 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5344 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005345 }
5346
5347 BT_DBG("%s param_count %u", hdev->name, param_count);
5348
5349 hci_dev_lock(hdev);
5350
5351 hci_conn_params_clear_disabled(hdev);
5352
5353 for (i = 0; i < param_count; i++) {
5354 struct mgmt_conn_param *param = &cp->params[i];
5355 struct hci_conn_params *hci_param;
5356 u16 min, max, latency, timeout;
5357 u8 addr_type;
5358
5359 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5360 param->addr.type);
5361
5362 if (param->addr.type == BDADDR_LE_PUBLIC) {
5363 addr_type = ADDR_LE_DEV_PUBLIC;
5364 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5365 addr_type = ADDR_LE_DEV_RANDOM;
5366 } else {
5367 BT_ERR("Ignoring invalid connection parameters");
5368 continue;
5369 }
5370
5371 min = le16_to_cpu(param->min_interval);
5372 max = le16_to_cpu(param->max_interval);
5373 latency = le16_to_cpu(param->latency);
5374 timeout = le16_to_cpu(param->timeout);
5375
5376 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5377 min, max, latency, timeout);
5378
5379 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5380 BT_ERR("Ignoring invalid connection parameters");
5381 continue;
5382 }
5383
5384 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5385 addr_type);
5386 if (!hci_param) {
5387 BT_ERR("Failed to add connection parameters");
5388 continue;
5389 }
5390
5391 hci_param->conn_min_interval = min;
5392 hci_param->conn_max_interval = max;
5393 hci_param->conn_latency = latency;
5394 hci_param->supervision_timeout = timeout;
5395 }
5396
5397 hci_dev_unlock(hdev);
5398
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005399 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5400 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005401}
5402
Marcel Holtmanndbece372014-07-04 18:11:55 +02005403static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5404 void *data, u16 len)
5405{
5406 struct mgmt_cp_set_external_config *cp = data;
5407 bool changed;
5408 int err;
5409
5410 BT_DBG("%s", hdev->name);
5411
5412 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005413 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5414 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005415
5416 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005417 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5418 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005419
5420 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005421 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5422 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005423
5424 hci_dev_lock(hdev);
5425
5426 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005427 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005428 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005429 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005430
5431 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5432 if (err < 0)
5433 goto unlock;
5434
5435 if (!changed)
5436 goto unlock;
5437
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005438 err = new_options(hdev, sk);
5439
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005440 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005441 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005442
Marcel Holtmann516018a2015-03-13 02:11:04 -07005443 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005444 hci_dev_set_flag(hdev, HCI_CONFIG);
5445 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005446
5447 queue_work(hdev->req_workqueue, &hdev->power_on);
5448 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005449 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005450 mgmt_index_added(hdev);
5451 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005452 }
5453
5454unlock:
5455 hci_dev_unlock(hdev);
5456 return err;
5457}
5458
Marcel Holtmann9713c172014-07-06 12:11:15 +02005459static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5460 void *data, u16 len)
5461{
5462 struct mgmt_cp_set_public_address *cp = data;
5463 bool changed;
5464 int err;
5465
5466 BT_DBG("%s", hdev->name);
5467
5468 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005469 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5470 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005471
5472 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5474 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005475
5476 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005477 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5478 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005479
5480 hci_dev_lock(hdev);
5481
5482 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5483 bacpy(&hdev->public_addr, &cp->bdaddr);
5484
5485 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5486 if (err < 0)
5487 goto unlock;
5488
5489 if (!changed)
5490 goto unlock;
5491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005492 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005493 err = new_options(hdev, sk);
5494
5495 if (is_configured(hdev)) {
5496 mgmt_index_removed(hdev);
5497
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005498 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005499
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005500 hci_dev_set_flag(hdev, HCI_CONFIG);
5501 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005502
5503 queue_work(hdev->req_workqueue, &hdev->power_on);
5504 }
5505
5506unlock:
5507 hci_dev_unlock(hdev);
5508 return err;
5509}
5510
Marcel Holtmannbea41602015-03-14 22:43:17 -07005511static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5512 u8 data_len)
5513{
5514 eir[eir_len++] = sizeof(type) + data_len;
5515 eir[eir_len++] = type;
5516 memcpy(&eir[eir_len], data, data_len);
5517 eir_len += data_len;
5518
5519 return eir_len;
5520}
5521
Johan Hedberg40f66c02015-04-07 21:52:22 +03005522static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5523 u16 opcode, struct sk_buff *skb)
5524{
5525 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5526 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5527 u8 *h192, *r192, *h256, *r256;
5528 struct mgmt_pending_cmd *cmd;
5529 u16 eir_len;
5530 int err;
5531
5532 BT_DBG("%s status %u", hdev->name, status);
5533
5534 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5535 if (!cmd)
5536 return;
5537
5538 mgmt_cp = cmd->param;
5539
5540 if (status) {
5541 status = mgmt_status(status);
5542 eir_len = 0;
5543
5544 h192 = NULL;
5545 r192 = NULL;
5546 h256 = NULL;
5547 r256 = NULL;
5548 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5549 struct hci_rp_read_local_oob_data *rp;
5550
5551 if (skb->len != sizeof(*rp)) {
5552 status = MGMT_STATUS_FAILED;
5553 eir_len = 0;
5554 } else {
5555 status = MGMT_STATUS_SUCCESS;
5556 rp = (void *)skb->data;
5557
5558 eir_len = 5 + 18 + 18;
5559 h192 = rp->hash;
5560 r192 = rp->rand;
5561 h256 = NULL;
5562 r256 = NULL;
5563 }
5564 } else {
5565 struct hci_rp_read_local_oob_ext_data *rp;
5566
5567 if (skb->len != sizeof(*rp)) {
5568 status = MGMT_STATUS_FAILED;
5569 eir_len = 0;
5570 } else {
5571 status = MGMT_STATUS_SUCCESS;
5572 rp = (void *)skb->data;
5573
5574 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5575 eir_len = 5 + 18 + 18;
5576 h192 = NULL;
5577 r192 = NULL;
5578 } else {
5579 eir_len = 5 + 18 + 18 + 18 + 18;
5580 h192 = rp->hash192;
5581 r192 = rp->rand192;
5582 }
5583
5584 h256 = rp->hash256;
5585 r256 = rp->rand256;
5586 }
5587 }
5588
5589 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5590 if (!mgmt_rp)
5591 goto done;
5592
5593 if (status)
5594 goto send_rsp;
5595
5596 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5597 hdev->dev_class, 3);
5598
5599 if (h192 && r192) {
5600 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5601 EIR_SSP_HASH_C192, h192, 16);
5602 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5603 EIR_SSP_RAND_R192, r192, 16);
5604 }
5605
5606 if (h256 && r256) {
5607 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5608 EIR_SSP_HASH_C256, h256, 16);
5609 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5610 EIR_SSP_RAND_R256, r256, 16);
5611 }
5612
5613send_rsp:
5614 mgmt_rp->type = mgmt_cp->type;
5615 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5616
5617 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5618 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5619 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5620 if (err < 0 || status)
5621 goto done;
5622
5623 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5624
5625 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5626 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5627 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5628done:
5629 kfree(mgmt_rp);
5630 mgmt_pending_remove(cmd);
5631}
5632
5633static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5634 struct mgmt_cp_read_local_oob_ext_data *cp)
5635{
5636 struct mgmt_pending_cmd *cmd;
5637 struct hci_request req;
5638 int err;
5639
5640 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5641 cp, sizeof(*cp));
5642 if (!cmd)
5643 return -ENOMEM;
5644
5645 hci_req_init(&req, hdev);
5646
5647 if (bredr_sc_enabled(hdev))
5648 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5649 else
5650 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5651
5652 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5653 if (err < 0) {
5654 mgmt_pending_remove(cmd);
5655 return err;
5656 }
5657
5658 return 0;
5659}
5660
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005661static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5662 void *data, u16 data_len)
5663{
5664 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5665 struct mgmt_rp_read_local_oob_ext_data *rp;
5666 size_t rp_len;
5667 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005668 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005669 int err;
5670
5671 BT_DBG("%s", hdev->name);
5672
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005673 if (hdev_is_powered(hdev)) {
5674 switch (cp->type) {
5675 case BIT(BDADDR_BREDR):
5676 status = mgmt_bredr_support(hdev);
5677 if (status)
5678 eir_len = 0;
5679 else
5680 eir_len = 5;
5681 break;
5682 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5683 status = mgmt_le_support(hdev);
5684 if (status)
5685 eir_len = 0;
5686 else
5687 eir_len = 9 + 3 + 18 + 18 + 3;
5688 break;
5689 default:
5690 status = MGMT_STATUS_INVALID_PARAMS;
5691 eir_len = 0;
5692 break;
5693 }
5694 } else {
5695 status = MGMT_STATUS_NOT_POWERED;
5696 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005697 }
5698
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005699 rp_len = sizeof(*rp) + eir_len;
5700 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005701 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005702 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005703
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005704 if (status)
5705 goto complete;
5706
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005707 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005708
5709 eir_len = 0;
5710 switch (cp->type) {
5711 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005712 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5713 err = read_local_ssp_oob_req(hdev, sk, cp);
5714 hci_dev_unlock(hdev);
5715 if (!err)
5716 goto done;
5717
5718 status = MGMT_STATUS_FAILED;
5719 goto complete;
5720 } else {
5721 eir_len = eir_append_data(rp->eir, eir_len,
5722 EIR_CLASS_OF_DEV,
5723 hdev->dev_class, 3);
5724 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005725 break;
5726 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005727 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5728 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005729 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005730 status = MGMT_STATUS_FAILED;
5731 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005732 }
5733
Marcel Holtmanne2135682015-04-02 12:00:58 -07005734 /* This should return the active RPA, but since the RPA
5735 * is only programmed on demand, it is really hard to fill
5736 * this in at the moment. For now disallow retrieving
5737 * local out-of-band data when privacy is in use.
5738 *
5739 * Returning the identity address will not help here since
5740 * pairing happens before the identity resolving key is
5741 * known and thus the connection establishment happens
5742 * based on the RPA and not the identity address.
5743 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005744 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005745 hci_dev_unlock(hdev);
5746 status = MGMT_STATUS_REJECTED;
5747 goto complete;
5748 }
5749
5750 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5751 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5752 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5753 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005754 memcpy(addr, &hdev->static_addr, 6);
5755 addr[6] = 0x01;
5756 } else {
5757 memcpy(addr, &hdev->bdaddr, 6);
5758 addr[6] = 0x00;
5759 }
5760
5761 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5762 addr, sizeof(addr));
5763
5764 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5765 role = 0x02;
5766 else
5767 role = 0x01;
5768
5769 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5770 &role, sizeof(role));
5771
Marcel Holtmann5082a592015-03-16 12:39:00 -07005772 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5773 eir_len = eir_append_data(rp->eir, eir_len,
5774 EIR_LE_SC_CONFIRM,
5775 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005776
Marcel Holtmann5082a592015-03-16 12:39:00 -07005777 eir_len = eir_append_data(rp->eir, eir_len,
5778 EIR_LE_SC_RANDOM,
5779 rand, sizeof(rand));
5780 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005781
Johan Hedbergf2252572015-11-18 12:49:20 +02005782 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005783
5784 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5785 flags |= LE_AD_NO_BREDR;
5786
5787 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5788 &flags, sizeof(flags));
5789 break;
5790 }
5791
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005792 hci_dev_unlock(hdev);
5793
Marcel Holtmann72000df2015-03-16 16:11:21 -07005794 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5795
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005796 status = MGMT_STATUS_SUCCESS;
5797
5798complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005799 rp->type = cp->type;
5800 rp->eir_len = cpu_to_le16(eir_len);
5801
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005802 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005803 status, rp, sizeof(*rp) + eir_len);
5804 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005805 goto done;
5806
5807 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5808 rp, sizeof(*rp) + eir_len,
5809 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005810
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005811done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005812 kfree(rp);
5813
5814 return err;
5815}
5816
Arman Uguray089fa8c2015-03-25 18:53:45 -07005817static u32 get_supported_adv_flags(struct hci_dev *hdev)
5818{
5819 u32 flags = 0;
5820
5821 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5822 flags |= MGMT_ADV_FLAG_DISCOV;
5823 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5824 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5825
5826 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5827 flags |= MGMT_ADV_FLAG_TX_POWER;
5828
5829 return flags;
5830}
5831
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005832static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5833 void *data, u16 data_len)
5834{
5835 struct mgmt_rp_read_adv_features *rp;
5836 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005837 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005838 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005839 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005840 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005841
5842 BT_DBG("%s", hdev->name);
5843
Arman Uguray089fa8c2015-03-25 18:53:45 -07005844 if (!lmp_le_capable(hdev))
5845 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5846 MGMT_STATUS_REJECTED);
5847
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005848 hci_dev_lock(hdev);
5849
Johan Hedberg02c04af2015-11-26 12:15:58 +02005850 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005851 rp = kmalloc(rp_len, GFP_ATOMIC);
5852 if (!rp) {
5853 hci_dev_unlock(hdev);
5854 return -ENOMEM;
5855 }
5856
Arman Uguray089fa8c2015-03-25 18:53:45 -07005857 supported_flags = get_supported_adv_flags(hdev);
5858
5859 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005860 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5861 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005862 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005863 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005864
Johan Hedberg02c04af2015-11-26 12:15:58 +02005865 instance = rp->instance;
5866 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5867 *instance = adv_instance->instance;
5868 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005869 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005870
5871 hci_dev_unlock(hdev);
5872
5873 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5874 MGMT_STATUS_SUCCESS, rp, rp_len);
5875
5876 kfree(rp);
5877
5878 return err;
5879}
5880
Arman Uguray4117ed72015-03-23 15:57:14 -07005881static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005882 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005883{
Arman Uguray4117ed72015-03-23 15:57:14 -07005884 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005885 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005886 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005887 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005888
Marcel Holtmann31a32482015-11-19 16:16:42 +01005889 if (is_adv_data) {
5890 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5891 MGMT_ADV_FLAG_LIMITED_DISCOV |
5892 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5893 flags_managed = true;
5894 max_len -= 3;
5895 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005896
Marcel Holtmann31a32482015-11-19 16:16:42 +01005897 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5898 tx_power_managed = true;
5899 max_len -= 3;
5900 }
Arman Uguray5507e352015-03-25 18:53:44 -07005901 }
5902
Arman Uguray4117ed72015-03-23 15:57:14 -07005903 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005904 return false;
5905
Arman Uguray4117ed72015-03-23 15:57:14 -07005906 /* Make sure that the data is correctly formatted. */
5907 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5908 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005909
Arman Ugurayb44133f2015-03-25 18:53:41 -07005910 if (flags_managed && data[i + 1] == EIR_FLAGS)
5911 return false;
5912
Arman Uguray5507e352015-03-25 18:53:44 -07005913 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5914 return false;
5915
Arman Uguray24b4f382015-03-23 15:57:12 -07005916 /* If the current field length would exceed the total data
5917 * length, then it's invalid.
5918 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005919 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005920 return false;
5921 }
5922
5923 return true;
5924}
5925
Arman Uguray24b4f382015-03-23 15:57:12 -07005926static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5927 u16 opcode)
5928{
5929 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005930 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005931 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005932 struct adv_info *adv_instance, *n;
5933 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005934
5935 BT_DBG("status %d", status);
5936
5937 hci_dev_lock(hdev);
5938
5939 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5940
Florian Grandelfffd38b2015-06-18 03:16:47 +02005941 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5942 if (!adv_instance->pending)
5943 continue;
5944
5945 if (!status) {
5946 adv_instance->pending = false;
5947 continue;
5948 }
5949
5950 instance = adv_instance->instance;
5951
5952 if (hdev->cur_adv_instance == instance)
5953 cancel_adv_timeout(hdev);
5954
5955 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02005956 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07005957 }
5958
5959 if (!cmd)
5960 goto unlock;
5961
Florian Grandelfffd38b2015-06-18 03:16:47 +02005962 cp = cmd->param;
5963 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005964
5965 if (status)
5966 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5967 mgmt_status(status));
5968 else
5969 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
5970 mgmt_status(status), &rp, sizeof(rp));
5971
5972 mgmt_pending_remove(cmd);
5973
5974unlock:
5975 hci_dev_unlock(hdev);
5976}
5977
5978static int add_advertising(struct sock *sk, struct hci_dev *hdev,
5979 void *data, u16 data_len)
5980{
5981 struct mgmt_cp_add_advertising *cp = data;
5982 struct mgmt_rp_add_advertising rp;
5983 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005984 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07005985 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005986 u16 timeout, duration;
5987 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
5988 u8 schedule_instance = 0;
5989 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005990 int err;
5991 struct mgmt_pending_cmd *cmd;
5992 struct hci_request req;
5993
5994 BT_DBG("%s", hdev->name);
5995
5996 status = mgmt_le_support(hdev);
5997 if (status)
5998 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5999 status);
6000
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006001 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6002 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6003 MGMT_STATUS_INVALID_PARAMS);
6004
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006005 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6006 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6007 MGMT_STATUS_INVALID_PARAMS);
6008
Arman Uguray24b4f382015-03-23 15:57:12 -07006009 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006010 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006011 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006012
Florian Grandelfffd38b2015-06-18 03:16:47 +02006013 /* The current implementation only supports a subset of the specified
6014 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006015 */
6016 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006017 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006018 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6019 MGMT_STATUS_INVALID_PARAMS);
6020
6021 hci_dev_lock(hdev);
6022
Arman Uguray912098a2015-03-23 15:57:15 -07006023 if (timeout && !hdev_is_powered(hdev)) {
6024 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6025 MGMT_STATUS_REJECTED);
6026 goto unlock;
6027 }
6028
Arman Uguray24b4f382015-03-23 15:57:12 -07006029 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006030 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006031 pending_find(MGMT_OP_SET_LE, hdev)) {
6032 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6033 MGMT_STATUS_BUSY);
6034 goto unlock;
6035 }
6036
Arman Ugurayb44133f2015-03-25 18:53:41 -07006037 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006038 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006039 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006040 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6041 MGMT_STATUS_INVALID_PARAMS);
6042 goto unlock;
6043 }
6044
Florian Grandelfffd38b2015-06-18 03:16:47 +02006045 err = hci_add_adv_instance(hdev, cp->instance, flags,
6046 cp->adv_data_len, cp->data,
6047 cp->scan_rsp_len,
6048 cp->data + cp->adv_data_len,
6049 timeout, duration);
6050 if (err < 0) {
6051 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6052 MGMT_STATUS_FAILED);
6053 goto unlock;
6054 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006055
Florian Grandelfffd38b2015-06-18 03:16:47 +02006056 /* Only trigger an advertising added event if a new instance was
6057 * actually added.
6058 */
6059 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006060 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006061
Florian Grandelfffd38b2015-06-18 03:16:47 +02006062 if (hdev->cur_adv_instance == cp->instance) {
6063 /* If the currently advertised instance is being changed then
6064 * cancel the current advertising and schedule the next
6065 * instance. If there is only one instance then the overridden
6066 * advertising data will be visible right away.
6067 */
6068 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006069
Florian Grandelfffd38b2015-06-18 03:16:47 +02006070 next_instance = hci_get_next_instance(hdev, cp->instance);
6071 if (next_instance)
6072 schedule_instance = next_instance->instance;
6073 } else if (!hdev->adv_instance_timeout) {
6074 /* Immediately advertise the new instance if no other
6075 * instance is currently being advertised.
6076 */
6077 schedule_instance = cp->instance;
6078 }
Arman Uguray912098a2015-03-23 15:57:15 -07006079
Florian Grandelfffd38b2015-06-18 03:16:47 +02006080 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6081 * there is no instance to be advertised then we have no HCI
6082 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006083 */
6084 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006085 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6086 !schedule_instance) {
6087 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006088 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6089 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6090 goto unlock;
6091 }
6092
6093 /* We're good to go, update advertising data, parameters, and start
6094 * advertising.
6095 */
6096 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6097 data_len);
6098 if (!cmd) {
6099 err = -ENOMEM;
6100 goto unlock;
6101 }
6102
6103 hci_req_init(&req, hdev);
6104
Johan Hedbergf2252572015-11-18 12:49:20 +02006105 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006106
Florian Grandelfffd38b2015-06-18 03:16:47 +02006107 if (!err)
6108 err = hci_req_run(&req, add_advertising_complete);
6109
Arman Uguray24b4f382015-03-23 15:57:12 -07006110 if (err < 0)
6111 mgmt_pending_remove(cmd);
6112
6113unlock:
6114 hci_dev_unlock(hdev);
6115
6116 return err;
6117}
6118
Arman Ugurayda9293352015-03-23 15:57:13 -07006119static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6120 u16 opcode)
6121{
6122 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006123 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006124 struct mgmt_rp_remove_advertising rp;
6125
6126 BT_DBG("status %d", status);
6127
6128 hci_dev_lock(hdev);
6129
6130 /* A failure status here only means that we failed to disable
6131 * advertising. Otherwise, the advertising instance has been removed,
6132 * so report success.
6133 */
6134 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6135 if (!cmd)
6136 goto unlock;
6137
Florian Grandel01948332015-06-18 03:16:48 +02006138 cp = cmd->param;
6139 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006140
6141 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6142 &rp, sizeof(rp));
6143 mgmt_pending_remove(cmd);
6144
6145unlock:
6146 hci_dev_unlock(hdev);
6147}
6148
6149static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6150 void *data, u16 data_len)
6151{
6152 struct mgmt_cp_remove_advertising *cp = data;
6153 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006154 struct mgmt_pending_cmd *cmd;
6155 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006156 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006157
6158 BT_DBG("%s", hdev->name);
6159
Arman Ugurayda9293352015-03-23 15:57:13 -07006160 hci_dev_lock(hdev);
6161
Johan Hedberg952497b2015-06-18 21:05:31 +03006162 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006163 err = mgmt_cmd_status(sk, hdev->id,
6164 MGMT_OP_REMOVE_ADVERTISING,
6165 MGMT_STATUS_INVALID_PARAMS);
6166 goto unlock;
6167 }
6168
Arman Ugurayda9293352015-03-23 15:57:13 -07006169 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6170 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6171 pending_find(MGMT_OP_SET_LE, hdev)) {
6172 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6173 MGMT_STATUS_BUSY);
6174 goto unlock;
6175 }
6176
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006177 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006178 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6179 MGMT_STATUS_INVALID_PARAMS);
6180 goto unlock;
6181 }
6182
Florian Grandel01948332015-06-18 03:16:48 +02006183 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006184
Johan Hedbergf2252572015-11-18 12:49:20 +02006185 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006186
Florian Grandel01948332015-06-18 03:16:48 +02006187 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006188 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006189
Florian Grandel01948332015-06-18 03:16:48 +02006190 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6191 * flag is set or the device isn't powered then we have no HCI
6192 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006193 */
Florian Grandel01948332015-06-18 03:16:48 +02006194 if (skb_queue_empty(&req.cmd_q) ||
6195 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006196 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006197 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006198 err = mgmt_cmd_complete(sk, hdev->id,
6199 MGMT_OP_REMOVE_ADVERTISING,
6200 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6201 goto unlock;
6202 }
6203
6204 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6205 data_len);
6206 if (!cmd) {
6207 err = -ENOMEM;
6208 goto unlock;
6209 }
6210
Arman Ugurayda9293352015-03-23 15:57:13 -07006211 err = hci_req_run(&req, remove_advertising_complete);
6212 if (err < 0)
6213 mgmt_pending_remove(cmd);
6214
6215unlock:
6216 hci_dev_unlock(hdev);
6217
6218 return err;
6219}
6220
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006221static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6222{
6223 u8 max_len = HCI_MAX_AD_LENGTH;
6224
6225 if (is_adv_data) {
6226 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6227 MGMT_ADV_FLAG_LIMITED_DISCOV |
6228 MGMT_ADV_FLAG_MANAGED_FLAGS))
6229 max_len -= 3;
6230
6231 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6232 max_len -= 3;
6233 }
6234
6235 return max_len;
6236}
6237
6238static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6239 void *data, u16 data_len)
6240{
6241 struct mgmt_cp_get_adv_size_info *cp = data;
6242 struct mgmt_rp_get_adv_size_info rp;
6243 u32 flags, supported_flags;
6244 int err;
6245
6246 BT_DBG("%s", hdev->name);
6247
6248 if (!lmp_le_capable(hdev))
6249 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6250 MGMT_STATUS_REJECTED);
6251
6252 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6253 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6254 MGMT_STATUS_INVALID_PARAMS);
6255
6256 flags = __le32_to_cpu(cp->flags);
6257
6258 /* The current implementation only supports a subset of the specified
6259 * flags.
6260 */
6261 supported_flags = get_supported_adv_flags(hdev);
6262 if (flags & ~supported_flags)
6263 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6264 MGMT_STATUS_INVALID_PARAMS);
6265
6266 rp.instance = cp->instance;
6267 rp.flags = cp->flags;
6268 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6269 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6270
6271 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6272 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6273
6274 return err;
6275}
6276
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006277static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006278 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006279 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006280 HCI_MGMT_NO_HDEV |
6281 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006282 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006283 HCI_MGMT_NO_HDEV |
6284 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006285 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006286 HCI_MGMT_NO_HDEV |
6287 HCI_MGMT_UNTRUSTED },
6288 { read_controller_info, MGMT_READ_INFO_SIZE,
6289 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006290 { set_powered, MGMT_SETTING_SIZE },
6291 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6292 { set_connectable, MGMT_SETTING_SIZE },
6293 { set_fast_connectable, MGMT_SETTING_SIZE },
6294 { set_bondable, MGMT_SETTING_SIZE },
6295 { set_link_security, MGMT_SETTING_SIZE },
6296 { set_ssp, MGMT_SETTING_SIZE },
6297 { set_hs, MGMT_SETTING_SIZE },
6298 { set_le, MGMT_SETTING_SIZE },
6299 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6300 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6301 { add_uuid, MGMT_ADD_UUID_SIZE },
6302 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006303 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6304 HCI_MGMT_VAR_LEN },
6305 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6306 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006307 { disconnect, MGMT_DISCONNECT_SIZE },
6308 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6309 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6310 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6311 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6312 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6313 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6314 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6315 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6316 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6317 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6318 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006319 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6320 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6321 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006322 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6323 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6324 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6325 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6326 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6327 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6328 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6329 { set_advertising, MGMT_SETTING_SIZE },
6330 { set_bredr, MGMT_SETTING_SIZE },
6331 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6332 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6333 { set_secure_conn, MGMT_SETTING_SIZE },
6334 { set_debug_keys, MGMT_SETTING_SIZE },
6335 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006336 { load_irks, MGMT_LOAD_IRKS_SIZE,
6337 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006338 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6339 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6340 { add_device, MGMT_ADD_DEVICE_SIZE },
6341 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006342 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6343 HCI_MGMT_VAR_LEN },
6344 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006345 HCI_MGMT_NO_HDEV |
6346 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006347 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006348 HCI_MGMT_UNCONFIGURED |
6349 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006350 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6351 HCI_MGMT_UNCONFIGURED },
6352 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6353 HCI_MGMT_UNCONFIGURED },
6354 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6355 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006356 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006357 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006358 HCI_MGMT_NO_HDEV |
6359 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006360 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006361 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6362 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006363 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006364 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006365 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006366};
6367
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006368void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006369{
Marcel Holtmannced85542015-03-14 19:27:56 -07006370 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006371
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006372 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6373 return;
6374
Marcel Holtmannf9207332015-03-14 19:27:55 -07006375 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006376 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006377 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6378 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6379 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006380 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006381 } else {
6382 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6383 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006384 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006385 }
6386 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006387 case HCI_AMP:
6388 ev.type = 0x02;
6389 break;
6390 default:
6391 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006392 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006393
6394 ev.bus = hdev->bus;
6395
6396 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6397 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006398}
6399
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006400void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006401{
Marcel Holtmannced85542015-03-14 19:27:56 -07006402 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006403 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006404
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006405 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6406 return;
6407
Marcel Holtmannf9207332015-03-14 19:27:55 -07006408 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006409 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006410 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006411
Marcel Holtmannf9207332015-03-14 19:27:55 -07006412 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6413 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6414 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006415 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006416 } else {
6417 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6418 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006419 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006420 }
6421 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006422 case HCI_AMP:
6423 ev.type = 0x02;
6424 break;
6425 default:
6426 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006427 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006428
6429 ev.bus = hdev->bus;
6430
6431 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6432 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006433}
6434
Andre Guedes6046dc32014-02-26 20:21:51 -03006435/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006436static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006437{
6438 struct hci_conn_params *p;
6439
6440 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006441 /* Needed for AUTO_OFF case where might not "really"
6442 * have been powered off.
6443 */
6444 list_del_init(&p->action);
6445
6446 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006447 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006448 case HCI_AUTO_CONN_ALWAYS:
6449 list_add(&p->action, &hdev->pend_le_conns);
6450 break;
6451 case HCI_AUTO_CONN_REPORT:
6452 list_add(&p->action, &hdev->pend_le_reports);
6453 break;
6454 default:
6455 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006456 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006457 }
6458}
6459
Johan Hedberg2ff13892015-11-25 16:15:44 +02006460void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006461{
6462 struct cmd_lookup match = { NULL, hdev };
6463
Johan Hedberg2ff13892015-11-25 16:15:44 +02006464 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006465
Johan Hedberg2ff13892015-11-25 16:15:44 +02006466 hci_dev_lock(hdev);
6467
6468 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006469 restart_le_actions(hdev);
6470 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006471 }
6472
Johan Hedberg229ab392013-03-15 17:06:53 -05006473 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6474
6475 new_settings(hdev, match.sk);
6476
Johan Hedberg229ab392013-03-15 17:06:53 -05006477 if (match.sk)
6478 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006479
6480 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006481}
6482
Johan Hedberg2ff13892015-11-25 16:15:44 +02006483void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006484{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006485 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006486 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006487
Johan Hedberg229ab392013-03-15 17:06:53 -05006488 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006489
6490 /* If the power off is because of hdev unregistration let
6491 * use the appropriate INVALID_INDEX status. Otherwise use
6492 * NOT_POWERED. We cover both scenarios here since later in
6493 * mgmt_index_removed() any hci_conn callbacks will have already
6494 * been triggered, potentially causing misleading DISCONNECTED
6495 * status responses.
6496 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006497 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006498 status = MGMT_STATUS_INVALID_INDEX;
6499 else
6500 status = MGMT_STATUS_NOT_POWERED;
6501
6502 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006503
6504 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006505 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6506 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006507
Johan Hedberg2ff13892015-11-25 16:15:44 +02006508 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006509
6510 if (match.sk)
6511 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006512}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006513
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006514void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006515{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006516 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006517 u8 status;
6518
Johan Hedberg333ae952015-03-17 13:48:47 +02006519 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006520 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006521 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006522
6523 if (err == -ERFKILL)
6524 status = MGMT_STATUS_RFKILLED;
6525 else
6526 status = MGMT_STATUS_FAILED;
6527
Johan Hedberga69e8372015-03-06 21:08:53 +02006528 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006529
6530 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006531}
6532
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006533void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6534 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006535{
Johan Hedberg86742e12011-11-07 23:13:38 +02006536 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006537
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006538 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006539
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006540 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006541 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006542 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006543 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006544 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006545 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006546
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006547 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006548}
Johan Hedbergf7520542011-01-20 12:34:39 +02006549
Johan Hedbergd7b25452014-05-23 13:19:53 +03006550static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6551{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006552 switch (ltk->type) {
6553 case SMP_LTK:
6554 case SMP_LTK_SLAVE:
6555 if (ltk->authenticated)
6556 return MGMT_LTK_AUTHENTICATED;
6557 return MGMT_LTK_UNAUTHENTICATED;
6558 case SMP_LTK_P256:
6559 if (ltk->authenticated)
6560 return MGMT_LTK_P256_AUTH;
6561 return MGMT_LTK_P256_UNAUTH;
6562 case SMP_LTK_P256_DEBUG:
6563 return MGMT_LTK_P256_DEBUG;
6564 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006565
6566 return MGMT_LTK_UNAUTHENTICATED;
6567}
6568
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006569void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006570{
6571 struct mgmt_ev_new_long_term_key ev;
6572
6573 memset(&ev, 0, sizeof(ev));
6574
Marcel Holtmann5192d302014-02-19 17:11:58 -08006575 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006576 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006577 * to store long term keys. Their addresses will change the
6578 * next time around.
6579 *
6580 * Only when a remote device provides an identity address
6581 * make sure the long term key is stored. If the remote
6582 * identity is known, the long term keys are internally
6583 * mapped to the identity address. So allow static random
6584 * and public addresses here.
6585 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006586 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6587 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6588 ev.store_hint = 0x00;
6589 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006590 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006591
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006592 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006593 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006594 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006595 ev.key.enc_size = key->enc_size;
6596 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006597 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006598
Johan Hedberg2ceba532014-06-16 19:25:16 +03006599 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006600 ev.key.master = 1;
6601
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006602 /* Make sure we copy only the significant bytes based on the
6603 * encryption key size, and set the rest of the value to zeroes.
6604 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006605 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006606 memset(ev.key.val + key->enc_size, 0,
6607 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006608
Marcel Holtmann083368f2013-10-15 14:26:29 -07006609 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006610}
6611
Johan Hedbergcad20c22015-10-12 13:36:19 +02006612void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006613{
6614 struct mgmt_ev_new_irk ev;
6615
6616 memset(&ev, 0, sizeof(ev));
6617
Johan Hedbergcad20c22015-10-12 13:36:19 +02006618 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006619
Johan Hedberg95fbac82014-02-19 15:18:31 +02006620 bacpy(&ev.rpa, &irk->rpa);
6621 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6622 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6623 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6624
6625 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6626}
6627
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006628void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6629 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006630{
6631 struct mgmt_ev_new_csrk ev;
6632
6633 memset(&ev, 0, sizeof(ev));
6634
6635 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006636 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006637 * to store signature resolving keys. Their addresses will change
6638 * the next time around.
6639 *
6640 * Only when a remote device provides an identity address
6641 * make sure the signature resolving key is stored. So allow
6642 * static random and public addresses here.
6643 */
6644 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6645 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6646 ev.store_hint = 0x00;
6647 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006648 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006649
6650 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6651 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006652 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006653 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6654
6655 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6656}
6657
Andre Guedesffb5a8272014-07-01 18:10:11 -03006658void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006659 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6660 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006661{
6662 struct mgmt_ev_new_conn_param ev;
6663
Johan Hedbergc103aea2014-07-02 17:37:34 +03006664 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6665 return;
6666
Andre Guedesffb5a8272014-07-01 18:10:11 -03006667 memset(&ev, 0, sizeof(ev));
6668 bacpy(&ev.addr.bdaddr, bdaddr);
6669 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006670 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006671 ev.min_interval = cpu_to_le16(min_interval);
6672 ev.max_interval = cpu_to_le16(max_interval);
6673 ev.latency = cpu_to_le16(latency);
6674 ev.timeout = cpu_to_le16(timeout);
6675
6676 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6677}
6678
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006679void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6680 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006681{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006682 char buf[512];
6683 struct mgmt_ev_device_connected *ev = (void *) buf;
6684 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006685
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006686 bacpy(&ev->addr.bdaddr, &conn->dst);
6687 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006688
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006689 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006690
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006691 /* We must ensure that the EIR Data fields are ordered and
6692 * unique. Keep it simple for now and avoid the problem by not
6693 * adding any BR/EDR data to the LE adv.
6694 */
6695 if (conn->le_adv_data_len > 0) {
6696 memcpy(&ev->eir[eir_len],
6697 conn->le_adv_data, conn->le_adv_data_len);
6698 eir_len = conn->le_adv_data_len;
6699 } else {
6700 if (name_len > 0)
6701 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6702 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006703
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006704 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006705 eir_len = eir_append_data(ev->eir, eir_len,
6706 EIR_CLASS_OF_DEV,
6707 conn->dev_class, 3);
6708 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006709
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006710 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006711
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006712 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6713 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006714}
6715
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006716static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006717{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006718 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006719
Johan Hedbergf5818c22014-12-05 13:36:02 +02006720 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006721
6722 *sk = cmd->sk;
6723 sock_hold(*sk);
6724
Johan Hedberga664b5b2011-02-19 12:06:02 -03006725 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006726}
6727
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006728static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006729{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006730 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006731 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006732
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006733 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6734
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006735 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006736 mgmt_pending_remove(cmd);
6737}
6738
Johan Hedberg84c61d92014-08-01 11:13:30 +03006739bool mgmt_powering_down(struct hci_dev *hdev)
6740{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006741 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006742 struct mgmt_mode *cp;
6743
Johan Hedberg333ae952015-03-17 13:48:47 +02006744 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006745 if (!cmd)
6746 return false;
6747
6748 cp = cmd->param;
6749 if (!cp->val)
6750 return true;
6751
6752 return false;
6753}
6754
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006755void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006756 u8 link_type, u8 addr_type, u8 reason,
6757 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006758{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006759 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006760 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006761
Johan Hedberg84c61d92014-08-01 11:13:30 +03006762 /* The connection is still in hci_conn_hash so test for 1
6763 * instead of 0 to know if this is the last one.
6764 */
6765 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6766 cancel_delayed_work(&hdev->power_off);
6767 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006768 }
6769
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006770 if (!mgmt_connected)
6771 return;
6772
Andre Guedes57eb7762013-10-30 19:01:41 -03006773 if (link_type != ACL_LINK && link_type != LE_LINK)
6774 return;
6775
Johan Hedberg744cf192011-11-08 20:40:14 +02006776 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006777
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006778 bacpy(&ev.addr.bdaddr, bdaddr);
6779 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6780 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006781
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006782 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006783
6784 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006785 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006786
Johan Hedberg124f6e32012-02-09 13:50:12 +02006787 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006788 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006789}
6790
Marcel Holtmann78929242013-10-06 23:55:47 -07006791void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6792 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006793{
Andre Guedes3655bba2013-10-30 19:01:40 -03006794 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6795 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006796 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006797
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006798 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6799 hdev);
6800
Johan Hedberg333ae952015-03-17 13:48:47 +02006801 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006802 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006803 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006804
Andre Guedes3655bba2013-10-30 19:01:40 -03006805 cp = cmd->param;
6806
6807 if (bacmp(bdaddr, &cp->addr.bdaddr))
6808 return;
6809
6810 if (cp->addr.type != bdaddr_type)
6811 return;
6812
Johan Hedbergf5818c22014-12-05 13:36:02 +02006813 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006814 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006815}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006816
Marcel Holtmann445608d2013-10-06 23:55:48 -07006817void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6818 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006819{
6820 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006821
Johan Hedberg84c61d92014-08-01 11:13:30 +03006822 /* The connection is still in hci_conn_hash so test for 1
6823 * instead of 0 to know if this is the last one.
6824 */
6825 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6826 cancel_delayed_work(&hdev->power_off);
6827 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006828 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006829
Johan Hedberg4c659c32011-11-07 23:13:39 +02006830 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006831 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006832 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006833
Marcel Holtmann445608d2013-10-06 23:55:48 -07006834 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006835}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006836
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006837void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006838{
6839 struct mgmt_ev_pin_code_request ev;
6840
Johan Hedbergd8457692012-02-17 14:24:57 +02006841 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006842 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006843 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006844
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006845 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006846}
6847
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006848void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6849 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006850{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006851 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006852
Johan Hedberg333ae952015-03-17 13:48:47 +02006853 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006854 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006855 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006856
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006857 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006858 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006859}
6860
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006861void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6862 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006863{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006864 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006865
Johan Hedberg333ae952015-03-17 13:48:47 +02006866 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006867 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006868 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006869
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006870 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006871 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006872}
Johan Hedberga5c29682011-02-19 12:05:57 -03006873
Johan Hedberg744cf192011-11-08 20:40:14 +02006874int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006875 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006876 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006877{
6878 struct mgmt_ev_user_confirm_request ev;
6879
Johan Hedberg744cf192011-11-08 20:40:14 +02006880 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006881
Johan Hedberg272d90d2012-02-09 15:26:12 +02006882 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006883 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006884 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006885 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006886
Johan Hedberg744cf192011-11-08 20:40:14 +02006887 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006888 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006889}
6890
Johan Hedberg272d90d2012-02-09 15:26:12 +02006891int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006892 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006893{
6894 struct mgmt_ev_user_passkey_request ev;
6895
6896 BT_DBG("%s", hdev->name);
6897
Johan Hedberg272d90d2012-02-09 15:26:12 +02006898 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006899 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006900
6901 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006902 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006903}
6904
Brian Gix0df4c182011-11-16 13:53:13 -08006905static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006906 u8 link_type, u8 addr_type, u8 status,
6907 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006908{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006909 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006910
Johan Hedberg333ae952015-03-17 13:48:47 +02006911 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006912 if (!cmd)
6913 return -ENOENT;
6914
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006915 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006916 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006917
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006918 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006919}
6920
Johan Hedberg744cf192011-11-08 20:40:14 +02006921int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006922 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006923{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006924 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006925 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006926}
6927
Johan Hedberg272d90d2012-02-09 15:26:12 +02006928int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006929 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006930{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006931 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006932 status,
6933 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006934}
Johan Hedberg2a611692011-02-19 12:06:00 -03006935
Brian Gix604086b2011-11-23 08:28:33 -08006936int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006937 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006938{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006939 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006940 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006941}
6942
Johan Hedberg272d90d2012-02-09 15:26:12 +02006943int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006944 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006945{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006946 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006947 status,
6948 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006949}
6950
Johan Hedberg92a25252012-09-06 18:39:26 +03006951int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
6952 u8 link_type, u8 addr_type, u32 passkey,
6953 u8 entered)
6954{
6955 struct mgmt_ev_passkey_notify ev;
6956
6957 BT_DBG("%s", hdev->name);
6958
6959 bacpy(&ev.addr.bdaddr, bdaddr);
6960 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6961 ev.passkey = __cpu_to_le32(passkey);
6962 ev.entered = entered;
6963
6964 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
6965}
6966
Johan Hedberge1e930f2014-09-08 17:09:49 -07006967void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03006968{
6969 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006970 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07006971 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03006972
Johan Hedberge1e930f2014-09-08 17:09:49 -07006973 bacpy(&ev.addr.bdaddr, &conn->dst);
6974 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
6975 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03006976
Johan Hedberge1e930f2014-09-08 17:09:49 -07006977 cmd = find_pairing(conn);
6978
6979 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
6980 cmd ? cmd->sk : NULL);
6981
Johan Hedberga511b352014-12-11 21:45:45 +02006982 if (cmd) {
6983 cmd->cmd_complete(cmd, status);
6984 mgmt_pending_remove(cmd);
6985 }
Johan Hedberg2a611692011-02-19 12:06:00 -03006986}
Johan Hedbergb312b1612011-03-16 14:29:37 +02006987
Marcel Holtmann464996a2013-10-15 14:26:24 -07006988void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006989{
6990 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07006991 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006992
6993 if (status) {
6994 u8 mgmt_err = mgmt_status(status);
6995 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006996 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006997 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006998 }
6999
Marcel Holtmann464996a2013-10-15 14:26:24 -07007000 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007001 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007002 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007003 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007004
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007005 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007006 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007007
Johan Hedberg47990ea2012-02-22 11:58:37 +02007008 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007009 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007010
7011 if (match.sk)
7012 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007013}
7014
Johan Hedberg890ea892013-03-15 17:06:52 -05007015static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007016{
Johan Hedberg890ea892013-03-15 17:06:52 -05007017 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007018 struct hci_cp_write_eir cp;
7019
Johan Hedberg976eb202012-10-24 21:12:01 +03007020 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007021 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007022
Johan Hedbergc80da272012-02-22 15:38:48 +02007023 memset(hdev->eir, 0, sizeof(hdev->eir));
7024
Johan Hedbergcacaf522012-02-21 00:52:42 +02007025 memset(&cp, 0, sizeof(cp));
7026
Johan Hedberg890ea892013-03-15 17:06:52 -05007027 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007028}
7029
Marcel Holtmann3e248562013-10-15 14:26:25 -07007030void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007031{
7032 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007033 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007034 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007035
7036 if (status) {
7037 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007038
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007039 if (enable && hci_dev_test_and_clear_flag(hdev,
7040 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007041 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007042 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007043 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007044
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007045 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7046 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007047 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007048 }
7049
7050 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007051 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007052 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007053 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007054 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007055 changed = hci_dev_test_and_clear_flag(hdev,
7056 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007057 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007058 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007059 }
7060
7061 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7062
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007063 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007064 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007065
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007066 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007067 sock_put(match.sk);
7068
Johan Hedberg890ea892013-03-15 17:06:52 -05007069 hci_req_init(&req, hdev);
7070
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007071 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7072 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007073 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7074 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007075 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007076 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007077 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007078 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007079
7080 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007081}
7082
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007083static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007084{
7085 struct cmd_lookup *match = data;
7086
Johan Hedberg90e70452012-02-23 23:09:40 +02007087 if (match->sk == NULL) {
7088 match->sk = cmd->sk;
7089 sock_hold(match->sk);
7090 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007091}
7092
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007093void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7094 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007095{
Johan Hedberg90e70452012-02-23 23:09:40 +02007096 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007097
Johan Hedberg92da6092013-03-15 17:06:55 -05007098 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7099 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7100 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007101
7102 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007103 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7104 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007105
7106 if (match.sk)
7107 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007108}
7109
Marcel Holtmann7667da32013-10-15 14:26:27 -07007110void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007111{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007112 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007113 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007114
Johan Hedberg13928972013-03-15 17:07:00 -05007115 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007116 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007117
7118 memset(&ev, 0, sizeof(ev));
7119 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007120 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007121
Johan Hedberg333ae952015-03-17 13:48:47 +02007122 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007123 if (!cmd) {
7124 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007125
Johan Hedberg13928972013-03-15 17:07:00 -05007126 /* If this is a HCI command related to powering on the
7127 * HCI dev don't send any mgmt signals.
7128 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007129 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007130 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007131 }
7132
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007133 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7134 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007135}
Szymon Jancc35938b2011-03-22 13:12:21 +01007136
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007137static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7138{
7139 int i;
7140
7141 for (i = 0; i < uuid_count; i++) {
7142 if (!memcmp(uuid, uuids[i], 16))
7143 return true;
7144 }
7145
7146 return false;
7147}
7148
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007149static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7150{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007151 u16 parsed = 0;
7152
7153 while (parsed < eir_len) {
7154 u8 field_len = eir[0];
7155 u8 uuid[16];
7156 int i;
7157
7158 if (field_len == 0)
7159 break;
7160
7161 if (eir_len - parsed < field_len + 1)
7162 break;
7163
7164 switch (eir[1]) {
7165 case EIR_UUID16_ALL:
7166 case EIR_UUID16_SOME:
7167 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007168 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007169 uuid[13] = eir[i + 3];
7170 uuid[12] = eir[i + 2];
7171 if (has_uuid(uuid, uuid_count, uuids))
7172 return true;
7173 }
7174 break;
7175 case EIR_UUID32_ALL:
7176 case EIR_UUID32_SOME:
7177 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007178 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007179 uuid[15] = eir[i + 5];
7180 uuid[14] = eir[i + 4];
7181 uuid[13] = eir[i + 3];
7182 uuid[12] = eir[i + 2];
7183 if (has_uuid(uuid, uuid_count, uuids))
7184 return true;
7185 }
7186 break;
7187 case EIR_UUID128_ALL:
7188 case EIR_UUID128_SOME:
7189 for (i = 0; i + 17 <= field_len; i += 16) {
7190 memcpy(uuid, eir + i + 2, 16);
7191 if (has_uuid(uuid, uuid_count, uuids))
7192 return true;
7193 }
7194 break;
7195 }
7196
7197 parsed += field_len + 1;
7198 eir += field_len + 1;
7199 }
7200
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007201 return false;
7202}
7203
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007204static void restart_le_scan(struct hci_dev *hdev)
7205{
7206 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007207 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007208 return;
7209
7210 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7211 hdev->discovery.scan_start +
7212 hdev->discovery.scan_duration))
7213 return;
7214
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007215 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007216 DISCOV_LE_RESTART_DELAY);
7217}
7218
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007219static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7220 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7221{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007222 /* If a RSSI threshold has been specified, and
7223 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7224 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7225 * is set, let it through for further processing, as we might need to
7226 * restart the scan.
7227 *
7228 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7229 * the results are also dropped.
7230 */
7231 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7232 (rssi == HCI_RSSI_INVALID ||
7233 (rssi < hdev->discovery.rssi &&
7234 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7235 return false;
7236
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007237 if (hdev->discovery.uuid_count != 0) {
7238 /* If a list of UUIDs is provided in filter, results with no
7239 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007240 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007241 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7242 hdev->discovery.uuids) &&
7243 !eir_has_uuids(scan_rsp, scan_rsp_len,
7244 hdev->discovery.uuid_count,
7245 hdev->discovery.uuids))
7246 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007247 }
7248
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007249 /* If duplicate filtering does not report RSSI changes, then restart
7250 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007251 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007252 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7253 restart_le_scan(hdev);
7254
7255 /* Validate RSSI value against the RSSI threshold once more. */
7256 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7257 rssi < hdev->discovery.rssi)
7258 return false;
7259 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007260
7261 return true;
7262}
7263
Marcel Holtmann901801b2013-10-06 23:55:51 -07007264void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007265 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7266 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007267{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007268 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007269 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007270 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007271
Johan Hedberg75ce2082014-07-02 22:42:01 +03007272 /* Don't send events for a non-kernel initiated discovery. With
7273 * LE one exception is if we have pend_le_reports > 0 in which
7274 * case we're doing passive scanning and want these events.
7275 */
7276 if (!hci_discovery_active(hdev)) {
7277 if (link_type == ACL_LINK)
7278 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007279 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007280 return;
7281 }
Andre Guedes12602d02013-04-30 15:29:40 -03007282
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007283 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007284 /* We are using service discovery */
7285 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7286 scan_rsp_len))
7287 return;
7288 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007289
Johan Hedberg78b781c2016-01-05 13:19:32 +02007290 if (hdev->discovery.limited) {
7291 /* Check for limited discoverable bit */
7292 if (dev_class) {
7293 if (!(dev_class[1] & 0x20))
7294 return;
7295 } else {
7296 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7297 if (!flags || !(flags[0] & LE_AD_LIMITED))
7298 return;
7299 }
7300 }
7301
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007302 /* Make sure that the buffer is big enough. The 5 extra bytes
7303 * are for the potential CoD field.
7304 */
7305 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007306 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007307
Johan Hedberg1dc06092012-01-15 21:01:23 +02007308 memset(buf, 0, sizeof(buf));
7309
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007310 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7311 * RSSI value was reported as 0 when not available. This behavior
7312 * is kept when using device discovery. This is required for full
7313 * backwards compatibility with the API.
7314 *
7315 * However when using service discovery, the value 127 will be
7316 * returned when the RSSI is not available.
7317 */
Szymon Janc91200e92015-01-22 16:57:05 +01007318 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7319 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007320 rssi = 0;
7321
Johan Hedberg841c5642014-07-07 12:45:54 +03007322 bacpy(&ev->addr.bdaddr, bdaddr);
7323 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007324 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007325 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007326
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007327 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007328 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007329 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007330
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007331 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7332 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007333 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007334 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007335
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007336 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007337 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007338 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007339
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007340 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7341 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007342
Marcel Holtmann901801b2013-10-06 23:55:51 -07007343 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007344}
Johan Hedberga88a9652011-03-30 13:18:12 +03007345
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007346void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7347 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007348{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007349 struct mgmt_ev_device_found *ev;
7350 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7351 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007352
Johan Hedbergb644ba32012-01-17 21:48:47 +02007353 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007354
Johan Hedbergb644ba32012-01-17 21:48:47 +02007355 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007356
Johan Hedbergb644ba32012-01-17 21:48:47 +02007357 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007358 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007359 ev->rssi = rssi;
7360
7361 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007362 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007363
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007364 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007365
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007366 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007367}
Johan Hedberg314b2382011-04-27 10:29:57 -04007368
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007369void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007370{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007371 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007372
Andre Guedes343fb142011-11-22 17:14:19 -03007373 BT_DBG("%s discovering %u", hdev->name, discovering);
7374
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007375 memset(&ev, 0, sizeof(ev));
7376 ev.type = hdev->discovery.type;
7377 ev.discovering = discovering;
7378
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007379 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007380}
Antti Julku5e762442011-08-25 16:48:02 +03007381
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007382static struct hci_mgmt_chan chan = {
7383 .channel = HCI_CHANNEL_CONTROL,
7384 .handler_count = ARRAY_SIZE(mgmt_handlers),
7385 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007386 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007387};
7388
7389int mgmt_init(void)
7390{
7391 return hci_mgmt_chan_register(&chan);
7392}
7393
7394void mgmt_exit(void)
7395{
7396 hci_mgmt_chan_unregister(&chan);
7397}