blob: db2e5a2f4e03110323237fa29926572a2072517d [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"
Alain Michaud17896402020-06-11 02:01:57 +000039#include "mgmt_config.h"
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +020040#include "msft.h"
Luiz Augusto von Dentz01ce70b2021-09-20 15:59:37 -070041#include "eir.h"
Johan Hedberg03811012010-12-08 00:21:06 +020042
Johan Hedberg2da9c552012-02-17 14:39:28 +020043#define MGMT_VERSION 1
Marcel Holtmann43e59cb2021-06-15 21:23:35 +020044#define MGMT_REVISION 21
Johan Hedberg02d98122010-12-13 21:07:04 +020045
Johan Hedberge70bb2e2012-02-13 16:59:33 +020046static const u16 mgmt_commands[] = {
47 MGMT_OP_READ_INDEX_LIST,
48 MGMT_OP_READ_INFO,
49 MGMT_OP_SET_POWERED,
50 MGMT_OP_SET_DISCOVERABLE,
51 MGMT_OP_SET_CONNECTABLE,
52 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030053 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020054 MGMT_OP_SET_LINK_SECURITY,
55 MGMT_OP_SET_SSP,
56 MGMT_OP_SET_HS,
57 MGMT_OP_SET_LE,
58 MGMT_OP_SET_DEV_CLASS,
59 MGMT_OP_SET_LOCAL_NAME,
60 MGMT_OP_ADD_UUID,
61 MGMT_OP_REMOVE_UUID,
62 MGMT_OP_LOAD_LINK_KEYS,
63 MGMT_OP_LOAD_LONG_TERM_KEYS,
64 MGMT_OP_DISCONNECT,
65 MGMT_OP_GET_CONNECTIONS,
66 MGMT_OP_PIN_CODE_REPLY,
67 MGMT_OP_PIN_CODE_NEG_REPLY,
68 MGMT_OP_SET_IO_CAPABILITY,
69 MGMT_OP_PAIR_DEVICE,
70 MGMT_OP_CANCEL_PAIR_DEVICE,
71 MGMT_OP_UNPAIR_DEVICE,
72 MGMT_OP_USER_CONFIRM_REPLY,
73 MGMT_OP_USER_CONFIRM_NEG_REPLY,
74 MGMT_OP_USER_PASSKEY_REPLY,
75 MGMT_OP_USER_PASSKEY_NEG_REPLY,
76 MGMT_OP_READ_LOCAL_OOB_DATA,
77 MGMT_OP_ADD_REMOTE_OOB_DATA,
78 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
79 MGMT_OP_START_DISCOVERY,
80 MGMT_OP_STOP_DISCOVERY,
81 MGMT_OP_CONFIRM_NAME,
82 MGMT_OP_BLOCK_DEVICE,
83 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070084 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030085 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030086 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070087 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070088 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080089 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080090 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020091 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020092 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020093 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030094 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020095 MGMT_OP_ADD_DEVICE,
96 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030097 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020098 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020099 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +0200100 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200101 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100102 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700103 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700104 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700105 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700106 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700107 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100108 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200109 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200110 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200111 MGMT_OP_SET_APPEARANCE,
Marcel Holtmann02431b62021-03-24 15:10:55 +0100112 MGMT_OP_GET_PHY_CONFIGURATION,
113 MGMT_OP_SET_PHY_CONFIGURATION,
Alain Michaud600a8742020-01-07 00:43:17 +0000114 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000115 MGMT_OP_SET_WIDEBAND_SPEECH,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800116 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200117 MGMT_OP_READ_EXP_FEATURES_INFO,
118 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000119 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
120 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200121 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
122 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200123 MGMT_OP_GET_DEVICE_FLAGS,
124 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200125 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200126 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200127 MGMT_OP_REMOVE_ADV_MONITOR,
Daniel Winkler12410572020-12-03 12:12:49 -0800128 MGMT_OP_ADD_EXT_ADV_PARAMS,
129 MGMT_OP_ADD_EXT_ADV_DATA,
Archie Pusakab4a221e2021-01-22 16:36:11 +0800130 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200131};
132
133static const u16 mgmt_events[] = {
134 MGMT_EV_CONTROLLER_ERROR,
135 MGMT_EV_INDEX_ADDED,
136 MGMT_EV_INDEX_REMOVED,
137 MGMT_EV_NEW_SETTINGS,
138 MGMT_EV_CLASS_OF_DEV_CHANGED,
139 MGMT_EV_LOCAL_NAME_CHANGED,
140 MGMT_EV_NEW_LINK_KEY,
141 MGMT_EV_NEW_LONG_TERM_KEY,
142 MGMT_EV_DEVICE_CONNECTED,
143 MGMT_EV_DEVICE_DISCONNECTED,
144 MGMT_EV_CONNECT_FAILED,
145 MGMT_EV_PIN_CODE_REQUEST,
146 MGMT_EV_USER_CONFIRM_REQUEST,
147 MGMT_EV_USER_PASSKEY_REQUEST,
148 MGMT_EV_AUTH_FAILED,
149 MGMT_EV_DEVICE_FOUND,
150 MGMT_EV_DISCOVERING,
151 MGMT_EV_DEVICE_BLOCKED,
152 MGMT_EV_DEVICE_UNBLOCKED,
153 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300154 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800155 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700156 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200157 MGMT_EV_DEVICE_ADDED,
158 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300159 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200160 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200161 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200162 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700163 MGMT_EV_EXT_INDEX_ADDED,
164 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700165 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700166 MGMT_EV_ADVERTISING_ADDED,
167 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200168 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200169 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200170 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200171 MGMT_EV_DEVICE_FLAGS_CHANGED,
Marcel Holtmann3d34a712021-03-24 15:10:56 +0100172 MGMT_EV_ADV_MONITOR_ADDED,
173 MGMT_EV_ADV_MONITOR_REMOVED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700174 MGMT_EV_CONTROLLER_SUSPEND,
175 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200176};
177
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700178static const u16 mgmt_untrusted_commands[] = {
179 MGMT_OP_READ_INDEX_LIST,
180 MGMT_OP_READ_INFO,
181 MGMT_OP_READ_UNCONF_INDEX_LIST,
182 MGMT_OP_READ_CONFIG_INFO,
183 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200184 MGMT_OP_READ_EXT_INFO,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800185 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200186 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000187 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200188 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700189};
190
191static const u16 mgmt_untrusted_events[] = {
192 MGMT_EV_INDEX_ADDED,
193 MGMT_EV_INDEX_REMOVED,
194 MGMT_EV_NEW_SETTINGS,
195 MGMT_EV_CLASS_OF_DEV_CHANGED,
196 MGMT_EV_LOCAL_NAME_CHANGED,
197 MGMT_EV_UNCONF_INDEX_ADDED,
198 MGMT_EV_UNCONF_INDEX_REMOVED,
199 MGMT_EV_NEW_CONFIG_OPTIONS,
200 MGMT_EV_EXT_INDEX_ADDED,
201 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200202 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200203 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700204};
205
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800206#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200207
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200208#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
209 "\x00\x00\x00\x00\x00\x00\x00\x00"
210
Johan Hedbergca69b792011-11-11 18:10:00 +0200211/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000212static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200213 MGMT_STATUS_SUCCESS,
214 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
215 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
216 MGMT_STATUS_FAILED, /* Hardware Failure */
217 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
218 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200219 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200220 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
221 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
222 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
223 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
224 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
225 MGMT_STATUS_BUSY, /* Command Disallowed */
226 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
227 MGMT_STATUS_REJECTED, /* Rejected Security */
228 MGMT_STATUS_REJECTED, /* Rejected Personal */
229 MGMT_STATUS_TIMEOUT, /* Host Timeout */
230 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
231 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
232 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
233 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
234 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
235 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
236 MGMT_STATUS_BUSY, /* Repeated Attempts */
237 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
238 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
239 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
240 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
241 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
242 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
243 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
244 MGMT_STATUS_FAILED, /* Unspecified Error */
245 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
246 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
247 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
248 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
249 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
250 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
251 MGMT_STATUS_FAILED, /* Unit Link Key Used */
252 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
253 MGMT_STATUS_TIMEOUT, /* Instant Passed */
254 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
255 MGMT_STATUS_FAILED, /* Transaction Collision */
Yu Liu4ef36a52021-04-19 16:53:30 -0700256 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200257 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
258 MGMT_STATUS_REJECTED, /* QoS Rejected */
259 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
260 MGMT_STATUS_REJECTED, /* Insufficient Security */
261 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
Yu Liu4ef36a52021-04-19 16:53:30 -0700262 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200263 MGMT_STATUS_BUSY, /* Role Switch Pending */
Yu Liu4ef36a52021-04-19 16:53:30 -0700264 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200265 MGMT_STATUS_FAILED, /* Slot Violation */
266 MGMT_STATUS_FAILED, /* Role Switch Failed */
267 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
268 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
269 MGMT_STATUS_BUSY, /* Host Busy Pairing */
270 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
271 MGMT_STATUS_BUSY, /* Controller Busy */
272 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
273 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
274 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
275 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
276 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
277};
278
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700279static u8 mgmt_errno_status(int err)
Johan Hedbergca69b792011-11-11 18:10:00 +0200280{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700281 switch (err) {
282 case 0:
283 return MGMT_STATUS_SUCCESS;
284 case -EPERM:
285 return MGMT_STATUS_REJECTED;
286 case -EINVAL:
287 return MGMT_STATUS_INVALID_PARAMS;
288 case -EOPNOTSUPP:
289 return MGMT_STATUS_NOT_SUPPORTED;
290 case -EBUSY:
291 return MGMT_STATUS_BUSY;
292 case -ETIMEDOUT:
293 return MGMT_STATUS_AUTH_FAILED;
294 case -ENOMEM:
295 return MGMT_STATUS_NO_RESOURCES;
296 case -EISCONN:
297 return MGMT_STATUS_ALREADY_CONNECTED;
298 case -ENOTCONN:
299 return MGMT_STATUS_DISCONNECTED;
300 }
301
302 return MGMT_STATUS_FAILED;
303}
304
305static u8 mgmt_status(int err)
306{
307 if (err < 0)
308 return mgmt_errno_status(err);
309
310 if (err < ARRAY_SIZE(mgmt_status_table))
311 return mgmt_status_table[err];
Johan Hedbergca69b792011-11-11 18:10:00 +0200312
313 return MGMT_STATUS_FAILED;
314}
315
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700316static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
317 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700318{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700319 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
320 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700321}
322
Marcel Holtmann72000df2015-03-16 16:11:21 -0700323static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
324 u16 len, int flag, struct sock *skip_sk)
325{
326 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
327 flag, skip_sk);
328}
329
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200330static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
331 struct sock *skip_sk)
332{
333 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700334 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200335}
336
Johan Hedberg85813a72015-10-21 18:02:59 +0300337static u8 le_addr_type(u8 mgmt_addr_type)
338{
339 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
340 return ADDR_LE_DEV_PUBLIC;
341 else
342 return ADDR_LE_DEV_RANDOM;
343}
344
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200345void mgmt_fill_version_info(void *ver)
346{
347 struct mgmt_rp_read_version *rp = ver;
348
349 rp->version = MGMT_VERSION;
350 rp->revision = cpu_to_le16(MGMT_REVISION);
351}
352
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
354 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200355{
356 struct mgmt_rp_read_version rp;
357
Marcel Holtmann181d6952020-05-06 09:57:47 +0200358 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200359
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200360 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200361
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200362 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
363 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200364}
365
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300366static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
367 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200368{
369 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700370 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200371 size_t rp_size;
372 int i, err;
373
Marcel Holtmann181d6952020-05-06 09:57:47 +0200374 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200375
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700376 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
377 num_commands = ARRAY_SIZE(mgmt_commands);
378 num_events = ARRAY_SIZE(mgmt_events);
379 } else {
380 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
381 num_events = ARRAY_SIZE(mgmt_untrusted_events);
382 }
383
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200384 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
385
386 rp = kmalloc(rp_size, GFP_KERNEL);
387 if (!rp)
388 return -ENOMEM;
389
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700390 rp->num_commands = cpu_to_le16(num_commands);
391 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200392
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700393 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
394 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200395
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700396 for (i = 0; i < num_commands; i++, opcode++)
397 put_unaligned_le16(mgmt_commands[i], opcode);
398
399 for (i = 0; i < num_events; i++, opcode++)
400 put_unaligned_le16(mgmt_events[i], opcode);
401 } else {
402 __le16 *opcode = rp->opcodes;
403
404 for (i = 0; i < num_commands; i++, opcode++)
405 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
406
407 for (i = 0; i < num_events; i++, opcode++)
408 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
409 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200410
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200411 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
412 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200413 kfree(rp);
414
415 return err;
416}
417
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300418static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
419 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200420{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200421 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200422 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200423 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200424 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300425 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200426
Marcel Holtmann181d6952020-05-06 09:57:47 +0200427 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428
429 read_lock(&hci_dev_list_lock);
430
431 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300432 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200433 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700434 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700435 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200436 }
437
Johan Hedberga38528f2011-01-22 06:46:43 +0200438 rp_len = sizeof(*rp) + (2 * count);
439 rp = kmalloc(rp_len, GFP_ATOMIC);
440 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100441 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200442 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100443 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200444
Johan Hedberg476e44c2012-10-19 20:10:46 +0300445 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200446 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 if (hci_dev_test_flag(d, HCI_SETUP) ||
448 hci_dev_test_flag(d, HCI_CONFIG) ||
449 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200450 continue;
451
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200452 /* Devices marked as raw-only are neither configured
453 * nor unconfigured controllers.
454 */
455 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700456 continue;
457
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200458 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700459 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700460 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200461 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700462 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200463 }
464
Johan Hedberg476e44c2012-10-19 20:10:46 +0300465 rp->num_controllers = cpu_to_le16(count);
466 rp_len = sizeof(*rp) + (2 * count);
467
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200468 read_unlock(&hci_dev_list_lock);
469
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200470 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
471 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200472
Johan Hedberga38528f2011-01-22 06:46:43 +0200473 kfree(rp);
474
475 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200476}
477
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200478static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
479 void *data, u16 data_len)
480{
481 struct mgmt_rp_read_unconf_index_list *rp;
482 struct hci_dev *d;
483 size_t rp_len;
484 u16 count;
485 int err;
486
Marcel Holtmann181d6952020-05-06 09:57:47 +0200487 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200488
489 read_lock(&hci_dev_list_lock);
490
491 count = 0;
492 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200493 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700494 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200495 count++;
496 }
497
498 rp_len = sizeof(*rp) + (2 * count);
499 rp = kmalloc(rp_len, GFP_ATOMIC);
500 if (!rp) {
501 read_unlock(&hci_dev_list_lock);
502 return -ENOMEM;
503 }
504
505 count = 0;
506 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700507 if (hci_dev_test_flag(d, HCI_SETUP) ||
508 hci_dev_test_flag(d, HCI_CONFIG) ||
509 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200510 continue;
511
512 /* Devices marked as raw-only are neither configured
513 * nor unconfigured controllers.
514 */
515 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
516 continue;
517
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200518 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700519 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200520 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200521 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200522 }
523 }
524
525 rp->num_controllers = cpu_to_le16(count);
526 rp_len = sizeof(*rp) + (2 * count);
527
528 read_unlock(&hci_dev_list_lock);
529
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200530 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
531 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200532
533 kfree(rp);
534
535 return err;
536}
537
Marcel Holtmann96f14742015-03-14 19:27:57 -0700538static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
539 void *data, u16 data_len)
540{
541 struct mgmt_rp_read_ext_index_list *rp;
542 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700543 u16 count;
544 int err;
545
Marcel Holtmann181d6952020-05-06 09:57:47 +0200546 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700547
548 read_lock(&hci_dev_list_lock);
549
550 count = 0;
551 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200552 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700553 count++;
554 }
555
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600556 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700557 if (!rp) {
558 read_unlock(&hci_dev_list_lock);
559 return -ENOMEM;
560 }
561
562 count = 0;
563 list_for_each_entry(d, &hci_dev_list, list) {
564 if (hci_dev_test_flag(d, HCI_SETUP) ||
565 hci_dev_test_flag(d, HCI_CONFIG) ||
566 hci_dev_test_flag(d, HCI_USER_CHANNEL))
567 continue;
568
569 /* Devices marked as raw-only are neither configured
570 * nor unconfigured controllers.
571 */
572 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
573 continue;
574
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200575 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700576 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
577 rp->entry[count].type = 0x01;
578 else
579 rp->entry[count].type = 0x00;
580 } else if (d->dev_type == HCI_AMP) {
581 rp->entry[count].type = 0x02;
582 } else {
583 continue;
584 }
585
586 rp->entry[count].bus = d->bus;
587 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200588 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700589 }
590
591 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700592
593 read_unlock(&hci_dev_list_lock);
594
595 /* If this command is called at least once, then all the
596 * default index and unconfigured index events are disabled
597 * and from now on only extended index events are used.
598 */
599 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
600 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
601 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
602
603 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600604 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
605 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700606
607 kfree(rp);
608
609 return err;
610}
611
Marcel Holtmanndbece372014-07-04 18:11:55 +0200612static bool is_configured(struct hci_dev *hdev)
613{
614 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700615 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200616 return false;
617
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800618 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
619 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200620 !bacmp(&hdev->public_addr, BDADDR_ANY))
621 return false;
622
623 return true;
624}
625
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200626static __le32 get_missing_options(struct hci_dev *hdev)
627{
628 u32 options = 0;
629
Marcel Holtmanndbece372014-07-04 18:11:55 +0200630 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700631 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200632 options |= MGMT_OPTION_EXTERNAL_CONFIG;
633
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800634 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
635 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200636 !bacmp(&hdev->public_addr, BDADDR_ANY))
637 options |= MGMT_OPTION_PUBLIC_ADDRESS;
638
639 return cpu_to_le32(options);
640}
641
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200642static int new_options(struct hci_dev *hdev, struct sock *skip)
643{
644 __le32 options = get_missing_options(hdev);
645
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200646 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
647 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200648}
649
Marcel Holtmanndbece372014-07-04 18:11:55 +0200650static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
651{
652 __le32 options = get_missing_options(hdev);
653
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200654 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
655 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200656}
657
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200658static int read_config_info(struct sock *sk, struct hci_dev *hdev,
659 void *data, u16 data_len)
660{
661 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200662 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200663
Marcel Holtmann181d6952020-05-06 09:57:47 +0200664 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200665
666 hci_dev_lock(hdev);
667
668 memset(&rp, 0, sizeof(rp));
669 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200670
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200671 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
672 options |= MGMT_OPTION_EXTERNAL_CONFIG;
673
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200674 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200675 options |= MGMT_OPTION_PUBLIC_ADDRESS;
676
677 rp.supported_options = cpu_to_le32(options);
678 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200679
680 hci_dev_unlock(hdev);
681
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200682 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
683 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200684}
685
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530686static u32 get_supported_phys(struct hci_dev *hdev)
687{
688 u32 supported_phys = 0;
689
690 if (lmp_bredr_capable(hdev)) {
691 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
692
693 if (hdev->features[0][0] & LMP_3SLOT)
694 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
695
696 if (hdev->features[0][0] & LMP_5SLOT)
697 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
698
699 if (lmp_edr_2m_capable(hdev)) {
700 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
701
702 if (lmp_edr_3slot_capable(hdev))
703 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
704
705 if (lmp_edr_5slot_capable(hdev))
706 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
707
708 if (lmp_edr_3m_capable(hdev)) {
709 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
710
711 if (lmp_edr_3slot_capable(hdev))
712 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
713
714 if (lmp_edr_5slot_capable(hdev))
715 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
716 }
717 }
718 }
719
720 if (lmp_le_capable(hdev)) {
721 supported_phys |= MGMT_PHY_LE_1M_TX;
722 supported_phys |= MGMT_PHY_LE_1M_RX;
723
724 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
725 supported_phys |= MGMT_PHY_LE_2M_TX;
726 supported_phys |= MGMT_PHY_LE_2M_RX;
727 }
728
729 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
730 supported_phys |= MGMT_PHY_LE_CODED_TX;
731 supported_phys |= MGMT_PHY_LE_CODED_RX;
732 }
733 }
734
735 return supported_phys;
736}
737
738static u32 get_selected_phys(struct hci_dev *hdev)
739{
740 u32 selected_phys = 0;
741
742 if (lmp_bredr_capable(hdev)) {
743 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
744
745 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
746 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
747
748 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
749 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
750
751 if (lmp_edr_2m_capable(hdev)) {
752 if (!(hdev->pkt_type & HCI_2DH1))
753 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
754
755 if (lmp_edr_3slot_capable(hdev) &&
756 !(hdev->pkt_type & HCI_2DH3))
757 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
758
759 if (lmp_edr_5slot_capable(hdev) &&
760 !(hdev->pkt_type & HCI_2DH5))
761 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
762
763 if (lmp_edr_3m_capable(hdev)) {
764 if (!(hdev->pkt_type & HCI_3DH1))
765 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
766
767 if (lmp_edr_3slot_capable(hdev) &&
768 !(hdev->pkt_type & HCI_3DH3))
769 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
770
771 if (lmp_edr_5slot_capable(hdev) &&
772 !(hdev->pkt_type & HCI_3DH5))
773 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
774 }
775 }
776 }
777
778 if (lmp_le_capable(hdev)) {
779 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
780 selected_phys |= MGMT_PHY_LE_1M_TX;
781
782 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
783 selected_phys |= MGMT_PHY_LE_1M_RX;
784
785 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
786 selected_phys |= MGMT_PHY_LE_2M_TX;
787
788 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
789 selected_phys |= MGMT_PHY_LE_2M_RX;
790
791 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
792 selected_phys |= MGMT_PHY_LE_CODED_TX;
793
794 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
795 selected_phys |= MGMT_PHY_LE_CODED_RX;
796 }
797
798 return selected_phys;
799}
800
801static u32 get_configurable_phys(struct hci_dev *hdev)
802{
803 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
804 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
805}
806
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200807static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200808{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200809 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200810
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200811 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300812 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800813 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300814 settings |= MGMT_SETTING_CONNECTABLE;
815 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200816
Andre Guedesed3fa312012-07-24 15:03:46 -0300817 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500818 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
819 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200820 settings |= MGMT_SETTING_BREDR;
821 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700822
823 if (lmp_ssp_capable(hdev)) {
824 settings |= MGMT_SETTING_SSP;
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -0700825 if (IS_ENABLED(CONFIG_BT_HS))
826 settings |= MGMT_SETTING_HS;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700827 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800828
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800829 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800830 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000831
Alain Michaud00bce3f2020-03-05 16:14:59 +0000832 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000833 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000834 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700835 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100836
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300837 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200838 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300839 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200840 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800841 settings |= MGMT_SETTING_STATIC_ADDRESS;
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -0700842 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300843 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200844
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200845 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
846 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200847 settings |= MGMT_SETTING_CONFIGURATION;
848
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530849 settings |= MGMT_SETTING_PHY_CONFIGURATION;
850
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200851 return settings;
852}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200853
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854static u32 get_current_settings(struct hci_dev *hdev)
855{
856 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200857
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200858 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100859 settings |= MGMT_SETTING_POWERED;
860
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862 settings |= MGMT_SETTING_CONNECTABLE;
863
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700864 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500865 settings |= MGMT_SETTING_FAST_CONNECTABLE;
866
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700867 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200868 settings |= MGMT_SETTING_DISCOVERABLE;
869
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700870 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300871 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700873 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 settings |= MGMT_SETTING_BREDR;
875
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700876 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200877 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200878
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700879 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200880 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200881
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700882 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200883 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200884
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700885 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200886 settings |= MGMT_SETTING_HS;
887
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700888 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300889 settings |= MGMT_SETTING_ADVERTISING;
890
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700891 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800892 settings |= MGMT_SETTING_SECURE_CONN;
893
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700894 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800895 settings |= MGMT_SETTING_DEBUG_KEYS;
896
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700897 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200898 settings |= MGMT_SETTING_PRIVACY;
899
Marcel Holtmann93690c22015-03-06 10:11:21 -0800900 /* The current setting for static address has two purposes. The
901 * first is to indicate if the static address will be used and
902 * the second is to indicate if it is actually set.
903 *
904 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700905 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800906 * address is actually used decides if the flag is set or not.
907 *
908 * For single mode LE only controllers and dual-mode controllers
909 * with BR/EDR disabled, the existence of the static address will
910 * be evaluated.
911 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700912 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700913 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800914 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
915 if (bacmp(&hdev->static_addr, BDADDR_ANY))
916 settings |= MGMT_SETTING_STATIC_ADDRESS;
917 }
918
Alain Michaud00bce3f2020-03-05 16:14:59 +0000919 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
920 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
921
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200922 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200923}
924
Johan Hedberg333ae952015-03-17 13:48:47 +0200925static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
926{
927 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
928}
929
Johan Hedberg333ae952015-03-17 13:48:47 +0200930static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
931 struct hci_dev *hdev,
932 const void *data)
933{
934 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
935}
936
Johan Hedbergf2252572015-11-18 12:49:20 +0200937u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300938{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200939 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300940
941 /* If there's a pending mgmt command the flags will not yet have
942 * their final values, so check for this first.
943 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200944 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300945 if (cmd) {
946 struct mgmt_mode *cp = cmd->param;
947 if (cp->val == 0x01)
948 return LE_AD_GENERAL;
949 else if (cp->val == 0x02)
950 return LE_AD_LIMITED;
951 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700952 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300953 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700954 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300955 return LE_AD_GENERAL;
956 }
957
958 return 0;
959}
960
Johan Hedbergf2252572015-11-18 12:49:20 +0200961bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700962{
963 struct mgmt_pending_cmd *cmd;
964
965 /* If there's a pending mgmt command the flag will not yet have
966 * it's final value, so check for this first.
967 */
968 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
969 if (cmd) {
970 struct mgmt_mode *cp = cmd->param;
971
972 return cp->val;
973 }
974
975 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
976}
977
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700978static int service_cache_sync(struct hci_dev *hdev, void *data)
979{
980 hci_update_eir_sync(hdev);
981 hci_update_class_sync(hdev);
982
983 return 0;
984}
985
Johan Hedberg7d785252011-12-15 00:47:39 +0200986static void service_cache_off(struct work_struct *work)
987{
988 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300989 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200990
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700991 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200992 return;
993
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700994 hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200995}
996
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -0700997static int rpa_expired_sync(struct hci_dev *hdev, void *data)
998{
999 /* The generation of a new RPA and programming it into the
1000 * controller happens in the hci_req_enable_advertising()
1001 * function.
1002 */
1003 if (ext_adv_capable(hdev))
1004 return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
1005 else
1006 return hci_enable_advertising_sync(hdev);
1007}
1008
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001009static void rpa_expired(struct work_struct *work)
1010{
1011 struct hci_dev *hdev = container_of(work, struct hci_dev,
1012 rpa_expired.work);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001013
Marcel Holtmann181d6952020-05-06 09:57:47 +02001014 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001015
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001016 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001017
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001018 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001019 return;
1020
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07001021 hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001022}
1023
Johan Hedberg6a919082012-02-28 06:17:26 +02001024static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001025{
Marcel Holtmann238be782015-03-13 02:11:06 -07001026 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001027 return;
1028
Johan Hedberg4f87da82012-03-02 19:55:56 +02001029 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001030 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001031
Johan Hedberg4f87da82012-03-02 19:55:56 +02001032 /* Non-mgmt controlled devices get this bit set
1033 * implicitly so that pairing works for them, however
1034 * for mgmt we require user-space to explicitly enable
1035 * it
1036 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001037 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001038}
1039
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001040static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001041 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001042{
1043 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001044
Marcel Holtmann181d6952020-05-06 09:57:47 +02001045 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001046
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001047 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001048
Johan Hedberg03811012010-12-08 00:21:06 +02001049 memset(&rp, 0, sizeof(rp));
1050
Johan Hedberg03811012010-12-08 00:21:06 +02001051 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001052
1053 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001054 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001055
1056 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1057 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1058
1059 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001060
1061 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001062 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001063
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001064 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001065
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001066 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1067 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001068}
1069
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001070static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1071{
1072 u16 eir_len = 0;
1073 size_t name_len;
1074
1075 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1076 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1077 hdev->dev_class, 3);
1078
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001079 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1080 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1081 hdev->appearance);
1082
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001083 name_len = strlen(hdev->dev_name);
1084 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1085 hdev->dev_name, name_len);
1086
1087 name_len = strlen(hdev->short_name);
1088 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1089 hdev->short_name, name_len);
1090
1091 return eir_len;
1092}
1093
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001094static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1095 void *data, u16 data_len)
1096{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001097 char buf[512];
1098 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001099 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001100
Marcel Holtmann181d6952020-05-06 09:57:47 +02001101 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001102
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001103 memset(&buf, 0, sizeof(buf));
1104
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001105 hci_dev_lock(hdev);
1106
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001107 bacpy(&rp->bdaddr, &hdev->bdaddr);
1108
1109 rp->version = hdev->hci_ver;
1110 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1111
1112 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1113 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001114
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001115
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001116 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001117 rp->eir_len = cpu_to_le16(eir_len);
1118
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001119 hci_dev_unlock(hdev);
1120
1121 /* If this command is called at least once, then the events
1122 * for class of device and local name changes are disabled
1123 * and only the new extended controller information event
1124 * is used.
1125 */
1126 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1127 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1128 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1129
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001130 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1131 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001132}
1133
1134static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1135{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001136 char buf[512];
1137 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1138 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001139
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001140 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001141
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001142 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1143 ev->eir_len = cpu_to_le16(eir_len);
1144
1145 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1146 sizeof(*ev) + eir_len,
1147 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001148}
1149
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001150static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001151{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001152 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001153
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001154 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1155 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001156}
1157
Johan Hedbergf2252572015-11-18 12:49:20 +02001158void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001159{
1160 struct mgmt_ev_advertising_added ev;
1161
1162 ev.instance = instance;
1163
1164 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1165}
1166
Johan Hedbergf2252572015-11-18 12:49:20 +02001167void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1168 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001169{
1170 struct mgmt_ev_advertising_removed ev;
1171
1172 ev.instance = instance;
1173
1174 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1175}
1176
Florian Grandel7816b822015-06-18 03:16:45 +02001177static void cancel_adv_timeout(struct hci_dev *hdev)
1178{
1179 if (hdev->adv_instance_timeout) {
1180 hdev->adv_instance_timeout = 0;
1181 cancel_delayed_work(&hdev->adv_instance_expire);
1182 }
1183}
1184
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001185/* This function requires the caller holds hdev->lock */
1186static void restart_le_actions(struct hci_dev *hdev)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001187{
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001188 struct hci_conn_params *p;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001189
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001190 list_for_each_entry(p, &hdev->le_conn_params, list) {
1191 /* Needed for AUTO_OFF case where might not "really"
1192 * have been powered off.
1193 */
1194 list_del_init(&p->action);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001195
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001196 switch (p->auto_connect) {
1197 case HCI_AUTO_CONN_DIRECT:
1198 case HCI_AUTO_CONN_ALWAYS:
1199 list_add(&p->action, &hdev->pend_le_conns);
1200 break;
1201 case HCI_AUTO_CONN_REPORT:
1202 list_add(&p->action, &hdev->pend_le_reports);
1203 break;
1204 default:
1205 break;
1206 }
1207 }
1208}
1209
1210static int new_settings(struct hci_dev *hdev, struct sock *skip)
1211{
1212 __le32 ev = cpu_to_le32(get_current_settings(hdev));
1213
1214 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1215 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
1216}
1217
1218static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
1219{
1220 struct mgmt_pending_cmd *cmd = data;
1221 struct mgmt_mode *cp = cmd->param;
1222
1223 bt_dev_dbg(hdev, "err %d", err);
1224
1225 if (!err) {
1226 if (cp->val) {
1227 hci_dev_lock(hdev);
1228 restart_le_actions(hdev);
1229 hci_update_passive_scan(hdev);
1230 hci_dev_unlock(hdev);
1231 }
1232
1233 send_settings_rsp(cmd->sk, cmd->opcode, hdev);
1234
1235 /* Only call new_setting for power on as power off is deferred
1236 * to hdev->power_off work which does call hci_dev_do_close.
1237 */
1238 if (cp->val)
1239 new_settings(hdev, cmd->sk);
1240 } else {
1241 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED,
1242 mgmt_status(err));
Johan Hedberg8b064a32014-02-24 14:52:22 +02001243 }
1244
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001245 mgmt_pending_free(cmd);
1246}
Arman Uguray912098a2015-03-23 15:57:15 -07001247
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001248static int set_powered_sync(struct hci_dev *hdev, void *data)
1249{
1250 struct mgmt_pending_cmd *cmd = data;
1251 struct mgmt_mode *cp = cmd->param;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001252
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001253 BT_DBG("%s", hdev->name);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001254
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001255 return hci_set_powered_sync(hdev, cp->val);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001256}
1257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001258static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001259 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001260{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001261 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001262 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001263 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001264
Marcel Holtmann181d6952020-05-06 09:57:47 +02001265 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001266
Johan Hedberga7e80f22013-01-09 16:05:19 +02001267 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001268 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1269 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001272
Johan Hedberg333ae952015-03-17 13:48:47 +02001273 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001274 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1275 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001276 goto failed;
1277 }
1278
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001279 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001280 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001281 goto failed;
1282 }
1283
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001284 cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001285 if (!cmd) {
1286 err = -ENOMEM;
1287 goto failed;
1288 }
1289
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001290 err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
1291 mgmt_set_powered_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001292
1293failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001294 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001295 return err;
1296}
1297
Johan Hedberg91a668b2014-07-09 13:28:26 +03001298int mgmt_new_settings(struct hci_dev *hdev)
1299{
1300 return new_settings(hdev, NULL);
1301}
1302
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001303struct cmd_lookup {
1304 struct sock *sk;
1305 struct hci_dev *hdev;
1306 u8 mgmt_status;
1307};
1308
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001309static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001310{
1311 struct cmd_lookup *match = data;
1312
1313 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1314
1315 list_del(&cmd->list);
1316
1317 if (match->sk == NULL) {
1318 match->sk = cmd->sk;
1319 sock_hold(match->sk);
1320 }
1321
1322 mgmt_pending_free(cmd);
1323}
1324
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001325static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001326{
1327 u8 *status = data;
1328
Johan Hedberga69e8372015-03-06 21:08:53 +02001329 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001330 mgmt_pending_remove(cmd);
1331}
1332
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001333static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001334{
1335 if (cmd->cmd_complete) {
1336 u8 *status = data;
1337
1338 cmd->cmd_complete(cmd, *status);
1339 mgmt_pending_remove(cmd);
1340
1341 return;
1342 }
1343
1344 cmd_status_rsp(cmd, data);
1345}
1346
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001348{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001349 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1350 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001351}
1352
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001353static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001354{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001355 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1356 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001357}
1358
Johan Hedberge6fe7982013-10-02 15:45:22 +03001359static u8 mgmt_bredr_support(struct hci_dev *hdev)
1360{
1361 if (!lmp_bredr_capable(hdev))
1362 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001363 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001364 return MGMT_STATUS_REJECTED;
1365 else
1366 return MGMT_STATUS_SUCCESS;
1367}
1368
1369static u8 mgmt_le_support(struct hci_dev *hdev)
1370{
1371 if (!lmp_le_capable(hdev))
1372 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001373 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001374 return MGMT_STATUS_REJECTED;
1375 else
1376 return MGMT_STATUS_SUCCESS;
1377}
1378
Johan Hedbergaed1a882015-11-22 17:24:44 +03001379void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001380{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001381 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001382
Marcel Holtmann181d6952020-05-06 09:57:47 +02001383 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001384
1385 hci_dev_lock(hdev);
1386
Johan Hedberg333ae952015-03-17 13:48:47 +02001387 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001388 if (!cmd)
1389 goto unlock;
1390
1391 if (status) {
1392 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001393 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001394 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001395 goto remove_cmd;
1396 }
1397
Johan Hedbergaed1a882015-11-22 17:24:44 +03001398 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1399 hdev->discov_timeout > 0) {
1400 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1401 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001402 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001403
1404 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001405 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001406
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001407remove_cmd:
1408 mgmt_pending_remove(cmd);
1409
1410unlock:
1411 hci_dev_unlock(hdev);
1412}
1413
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001414static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001415 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001416{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001417 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001418 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001419 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001420 int err;
1421
Marcel Holtmann181d6952020-05-06 09:57:47 +02001422 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001423
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001424 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1425 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001426 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1427 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001428
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001429 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001430 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1431 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001432
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001433 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001434
1435 /* Disabling discoverable requires that no timeout is set,
1436 * and enabling limited discoverable requires a timeout.
1437 */
1438 if ((cp->val == 0x00 && timeout > 0) ||
1439 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001440 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1441 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001443 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001444
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001445 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001446 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1447 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001448 goto failed;
1449 }
1450
Johan Hedberg333ae952015-03-17 13:48:47 +02001451 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1452 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001453 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1454 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001455 goto failed;
1456 }
1457
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001458 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001459 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1460 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001461 goto failed;
1462 }
1463
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001464 if (hdev->advertising_paused) {
1465 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1466 MGMT_STATUS_BUSY);
1467 goto failed;
1468 }
1469
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001470 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001471 bool changed = false;
1472
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001473 /* Setting limited discoverable when powered off is
1474 * not a valid operation since it requires a timeout
1475 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1476 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001477 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001478 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001479 changed = true;
1480 }
1481
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001482 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001483 if (err < 0)
1484 goto failed;
1485
1486 if (changed)
1487 err = new_settings(hdev, sk);
1488
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001489 goto failed;
1490 }
1491
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001492 /* If the current mode is the same, then just update the timeout
1493 * value with the new value. And if only the timeout gets updated,
1494 * then no need for any HCI transactions.
1495 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001496 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1497 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1498 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001499 cancel_delayed_work(&hdev->discov_off);
1500 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001501
Marcel Holtmann36261542013-10-15 08:28:51 -07001502 if (cp->val && hdev->discov_timeout > 0) {
1503 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001504 queue_delayed_work(hdev->req_workqueue,
1505 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001506 }
1507
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001508 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001509 goto failed;
1510 }
1511
1512 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1513 if (!cmd) {
1514 err = -ENOMEM;
1515 goto failed;
1516 }
1517
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001518 /* Cancel any potential discoverable timeout that might be
1519 * still active and store new timeout value. The arming of
1520 * the timeout happens in the complete handler.
1521 */
1522 cancel_delayed_work(&hdev->discov_off);
1523 hdev->discov_timeout = timeout;
1524
Johan Hedbergaed1a882015-11-22 17:24:44 +03001525 if (cp->val)
1526 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1527 else
1528 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1529
Johan Hedbergb456f872013-10-19 23:38:22 +03001530 /* Limited discoverable mode */
1531 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001532 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001533 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001534 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001535
Johan Hedbergaed1a882015-11-22 17:24:44 +03001536 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1537 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001538
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001539failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001540 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001541 return err;
1542}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001543
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001544void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001545{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001546 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001547
Marcel Holtmann181d6952020-05-06 09:57:47 +02001548 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001549
1550 hci_dev_lock(hdev);
1551
Johan Hedberg333ae952015-03-17 13:48:47 +02001552 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001553 if (!cmd)
1554 goto unlock;
1555
Johan Hedberg37438c12013-10-14 16:20:05 +03001556 if (status) {
1557 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001558 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001559 goto remove_cmd;
1560 }
1561
Johan Hedberg2b76f452013-03-15 17:07:04 -05001562 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001563 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001564
Johan Hedberg37438c12013-10-14 16:20:05 +03001565remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001566 mgmt_pending_remove(cmd);
1567
1568unlock:
1569 hci_dev_unlock(hdev);
1570}
1571
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001572static int set_connectable_update_settings(struct hci_dev *hdev,
1573 struct sock *sk, u8 val)
1574{
1575 bool changed = false;
1576 int err;
1577
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001578 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001579 changed = true;
1580
1581 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001582 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001583 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001584 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1585 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001586 }
1587
1588 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1589 if (err < 0)
1590 return err;
1591
Johan Hedberg562064e2014-07-08 16:35:34 +03001592 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001593 hci_req_update_scan(hdev);
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07001594 hci_update_passive_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001595 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001596 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001597
1598 return 0;
1599}
1600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001601static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001602 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001603{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001604 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001605 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001606 int err;
1607
Marcel Holtmann181d6952020-05-06 09:57:47 +02001608 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001609
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001610 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1611 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001612 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1613 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001614
Johan Hedberga7e80f22013-01-09 16:05:19 +02001615 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001616 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1617 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001619 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001620
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001621 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001622 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001623 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001624 }
1625
Johan Hedberg333ae952015-03-17 13:48:47 +02001626 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1627 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001628 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1629 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001630 goto failed;
1631 }
1632
Johan Hedberg73f22f62010-12-29 16:00:25 +02001633 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1634 if (!cmd) {
1635 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001636 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001637 }
1638
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001639 if (cp->val) {
1640 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1641 } else {
1642 if (hdev->discov_timeout > 0)
1643 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001644
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001645 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1646 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1647 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001648 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001649
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001650 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1651 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001652
1653failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001654 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001655 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001656}
1657
Johan Hedbergb2939472014-07-30 09:22:23 +03001658static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001660{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001661 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001662 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001663 int err;
1664
Marcel Holtmann181d6952020-05-06 09:57:47 +02001665 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001666
Johan Hedberga7e80f22013-01-09 16:05:19 +02001667 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001668 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1669 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001670
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001671 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001672
1673 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001674 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001675 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001676 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001677
Johan Hedbergb2939472014-07-30 09:22:23 +03001678 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001679 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001680 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001681
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001682 if (changed) {
1683 /* In limited privacy mode the change of bondable mode
1684 * may affect the local advertising address.
1685 */
1686 if (hdev_is_powered(hdev) &&
1687 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1688 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1689 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1690 queue_work(hdev->req_workqueue,
1691 &hdev->discoverable_update);
1692
Marcel Holtmann55594352013-10-06 16:11:57 -07001693 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001694 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001695
Marcel Holtmann55594352013-10-06 16:11:57 -07001696unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001697 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001698 return err;
1699}
1700
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001701static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1702 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001703{
1704 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001705 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001706 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001707 int err;
1708
Marcel Holtmann181d6952020-05-06 09:57:47 +02001709 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001710
Johan Hedberge6fe7982013-10-02 15:45:22 +03001711 status = mgmt_bredr_support(hdev);
1712 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1714 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001715
Johan Hedberga7e80f22013-01-09 16:05:19 +02001716 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1718 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001719
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001720 hci_dev_lock(hdev);
1721
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001722 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001723 bool changed = false;
1724
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001725 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001726 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001727 changed = true;
1728 }
1729
1730 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1731 if (err < 0)
1732 goto failed;
1733
1734 if (changed)
1735 err = new_settings(hdev, sk);
1736
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001737 goto failed;
1738 }
1739
Johan Hedberg333ae952015-03-17 13:48:47 +02001740 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001741 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1742 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001743 goto failed;
1744 }
1745
1746 val = !!cp->val;
1747
1748 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1749 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1750 goto failed;
1751 }
1752
1753 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1754 if (!cmd) {
1755 err = -ENOMEM;
1756 goto failed;
1757 }
1758
1759 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1760 if (err < 0) {
1761 mgmt_pending_remove(cmd);
1762 goto failed;
1763 }
1764
1765failed:
1766 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001767 return err;
1768}
1769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001770static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001771{
1772 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001773 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001774 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001775 int err;
1776
Marcel Holtmann181d6952020-05-06 09:57:47 +02001777 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001778
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001779 status = mgmt_bredr_support(hdev);
1780 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001781 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001782
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001783 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001784 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1785 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001786
Johan Hedberga7e80f22013-01-09 16:05:19 +02001787 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001788 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1789 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001790
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001791 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001792
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001793 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001794 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001795
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001796 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001797 changed = !hci_dev_test_and_set_flag(hdev,
1798 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001799 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001800 changed = hci_dev_test_and_clear_flag(hdev,
1801 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001802 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001803 changed = hci_dev_test_and_clear_flag(hdev,
1804 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001805 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001806 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001807 }
1808
1809 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1810 if (err < 0)
1811 goto failed;
1812
1813 if (changed)
1814 err = new_settings(hdev, sk);
1815
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001816 goto failed;
1817 }
1818
Johan Hedberg333ae952015-03-17 13:48:47 +02001819 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001820 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1821 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001822 goto failed;
1823 }
1824
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001825 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001826 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1827 goto failed;
1828 }
1829
1830 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1831 if (!cmd) {
1832 err = -ENOMEM;
1833 goto failed;
1834 }
1835
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001836 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001837 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1838 sizeof(cp->val), &cp->val);
1839
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001840 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001841 if (err < 0) {
1842 mgmt_pending_remove(cmd);
1843 goto failed;
1844 }
1845
1846failed:
1847 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001848 return err;
1849}
1850
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001851static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001852{
1853 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001854 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001855 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001856 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001857
Marcel Holtmann181d6952020-05-06 09:57:47 +02001858 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001859
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -07001860 if (!IS_ENABLED(CONFIG_BT_HS))
1861 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1862 MGMT_STATUS_NOT_SUPPORTED);
1863
Johan Hedberge6fe7982013-10-02 15:45:22 +03001864 status = mgmt_bredr_support(hdev);
1865 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001866 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001867
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001868 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001869 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1870 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001871
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001872 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001873 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1874 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001875
Johan Hedberga7e80f22013-01-09 16:05:19 +02001876 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001877 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001879
Marcel Holtmannee392692013-10-01 22:59:23 -07001880 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001881
Johan Hedberg333ae952015-03-17 13:48:47 +02001882 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001883 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1884 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001885 goto unlock;
1886 }
1887
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001888 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001889 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001890 } else {
1891 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001892 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1893 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001894 goto unlock;
1895 }
1896
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001897 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001898 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001899
1900 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1901 if (err < 0)
1902 goto unlock;
1903
1904 if (changed)
1905 err = new_settings(hdev, sk);
1906
1907unlock:
1908 hci_dev_unlock(hdev);
1909 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001910}
1911
Marcel Holtmann1904a852015-01-11 13:50:44 -08001912static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001913{
1914 struct cmd_lookup match = { NULL, hdev };
1915
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301916 hci_dev_lock(hdev);
1917
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001918 if (status) {
1919 u8 mgmt_err = mgmt_status(status);
1920
1921 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1922 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301923 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001924 }
1925
1926 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1927
1928 new_settings(hdev, match.sk);
1929
1930 if (match.sk)
1931 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001932
1933 /* Make sure the controller has a good default for
1934 * advertising data. Restrict the update to when LE
1935 * has actually been enabled. During power on, the
1936 * update in powered_update_hci will take care of it.
1937 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001938 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001939 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001940 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301941 if (ext_adv_capable(hdev)) {
1942 int err;
1943
1944 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1945 if (!err)
1946 __hci_req_update_scan_rsp_data(&req, 0x00);
1947 } else {
1948 __hci_req_update_adv_data(&req, 0x00);
1949 __hci_req_update_scan_rsp_data(&req, 0x00);
1950 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001951 hci_req_run(&req, NULL);
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07001952 hci_update_passive_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001953 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301954
1955unlock:
1956 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001957}
1958
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001960{
1961 struct mgmt_mode *cp = data;
1962 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001963 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001964 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001965 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001966 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001967
Marcel Holtmann181d6952020-05-06 09:57:47 +02001968 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001970 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001971 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1972 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001973
Johan Hedberga7e80f22013-01-09 16:05:19 +02001974 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001975 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1976 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001977
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001978 /* Bluetooth single mode LE only controllers or dual-mode
1979 * controllers configured as LE only devices, do not allow
1980 * switching LE off. These have either LE enabled explicitly
1981 * or BR/EDR has been previously switched off.
1982 *
1983 * When trying to enable an already enabled LE, then gracefully
1984 * send a positive response. Trying to disable it however will
1985 * result into rejection.
1986 */
1987 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1988 if (cp->val == 0x01)
1989 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1990
Johan Hedberga69e8372015-03-06 21:08:53 +02001991 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1992 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001993 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001994
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001995 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001996
1997 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001998 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001999
Florian Grandel847818d2015-06-18 03:16:46 +02002000 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03002001 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02002002
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002003 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002004 bool changed = false;
2005
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002006 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002007 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002008 changed = true;
2009 }
2010
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002011 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002012 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002013 changed = true;
2014 }
2015
Johan Hedberg06199cf2012-02-22 16:37:11 +02002016 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2017 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002018 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002019
2020 if (changed)
2021 err = new_settings(hdev, sk);
2022
Johan Hedberg1de028c2012-02-29 19:55:35 -08002023 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002024 }
2025
Johan Hedberg333ae952015-03-17 13:48:47 +02002026 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2027 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002028 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2029 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002030 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002031 }
2032
2033 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2034 if (!cmd) {
2035 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002036 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002037 }
2038
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002039 hci_req_init(&req, hdev);
2040
Johan Hedberg06199cf2012-02-22 16:37:11 +02002041 memset(&hci_cp, 0, sizeof(hci_cp));
2042
2043 if (val) {
2044 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002045 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002046 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002047 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002048 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05302049
2050 if (ext_adv_capable(hdev))
2051 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002052 }
2053
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002054 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2055 &hci_cp);
2056
2057 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302058 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002059 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002060
Johan Hedberg1de028c2012-02-29 19:55:35 -08002061unlock:
2062 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002063 return err;
2064}
2065
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002066/* This is a helper function to test for pending mgmt commands that can
2067 * cause CoD or EIR HCI commands. We can only allow one such pending
2068 * mgmt command at a time since otherwise we cannot easily track what
2069 * the current values are, will be, and based on that calculate if a new
2070 * HCI command needs to be sent and if yes with what value.
2071 */
2072static bool pending_eir_or_class(struct hci_dev *hdev)
2073{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002074 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002075
2076 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2077 switch (cmd->opcode) {
2078 case MGMT_OP_ADD_UUID:
2079 case MGMT_OP_REMOVE_UUID:
2080 case MGMT_OP_SET_DEV_CLASS:
2081 case MGMT_OP_SET_POWERED:
2082 return true;
2083 }
2084 }
2085
2086 return false;
2087}
2088
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002089static const u8 bluetooth_base_uuid[] = {
2090 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2091 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2092};
2093
2094static u8 get_uuid_size(const u8 *uuid)
2095{
2096 u32 val;
2097
2098 if (memcmp(uuid, bluetooth_base_uuid, 12))
2099 return 128;
2100
2101 val = get_unaligned_le32(&uuid[12]);
2102 if (val > 0xffff)
2103 return 32;
2104
2105 return 16;
2106}
2107
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002108static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg92da6092013-03-15 17:06:55 -05002109{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002110 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg92da6092013-03-15 17:06:55 -05002111
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002112 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg92da6092013-03-15 17:06:55 -05002113
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002114 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002115 mgmt_status(err), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002116
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002117 mgmt_pending_free(cmd);
Johan Hedberg92da6092013-03-15 17:06:55 -05002118}
2119
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002120static int add_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002121{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002122 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002123
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002124 err = hci_update_class_sync(hdev);
2125 if (err)
2126 return err;
2127
2128 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002129}
2130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002131static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002133 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002134 struct mgmt_pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002135 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002136 int err;
2137
Marcel Holtmann181d6952020-05-06 09:57:47 +02002138 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002140 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002141
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002142 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002143 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2144 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002145 goto failed;
2146 }
2147
Andre Guedes92c4c202012-06-07 19:05:44 -03002148 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002149 if (!uuid) {
2150 err = -ENOMEM;
2151 goto failed;
2152 }
2153
2154 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002155 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002156 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002157
Johan Hedbergde66aa62013-01-27 00:31:27 +02002158 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002160 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002161 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002162 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002163 goto failed;
2164 }
2165
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002166 err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete);
2167 if (err < 0) {
2168 mgmt_pending_free(cmd);
2169 goto failed;
2170 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002171
2172failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002174 return err;
2175}
2176
Johan Hedberg24b78d02012-02-23 23:24:30 +02002177static bool enable_service_cache(struct hci_dev *hdev)
2178{
2179 if (!hdev_is_powered(hdev))
2180 return false;
2181
Marcel Holtmann238be782015-03-13 02:11:06 -07002182 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002183 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2184 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002185 return true;
2186 }
2187
2188 return false;
2189}
2190
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002191static int remove_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002192{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002193 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002194
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002195 err = hci_update_class_sync(hdev);
2196 if (err)
2197 return err;
2198
2199 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002200}
2201
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002202static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002203 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002204{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002205 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002206 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002207 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002208 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002209 int err, found;
2210
Marcel Holtmann181d6952020-05-06 09:57:47 +02002211 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002212
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002213 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002214
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002215 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002216 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2217 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002218 goto unlock;
2219 }
2220
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002221 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002222 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002223
Johan Hedberg24b78d02012-02-23 23:24:30 +02002224 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002225 err = mgmt_cmd_complete(sk, hdev->id,
2226 MGMT_OP_REMOVE_UUID,
2227 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002228 goto unlock;
2229 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002230
Johan Hedberg9246a862012-02-23 21:33:16 +02002231 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002232 }
2233
2234 found = 0;
2235
Johan Hedberg056341c2013-01-27 00:31:30 +02002236 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002237 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2238 continue;
2239
2240 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002241 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002242 found++;
2243 }
2244
2245 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002246 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2247 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002248 goto unlock;
2249 }
2250
Johan Hedberg9246a862012-02-23 21:33:16 +02002251update_class:
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002252 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002253 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002254 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002255 goto unlock;
2256 }
2257
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002258 err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd,
2259 mgmt_class_complete);
2260 if (err < 0)
2261 mgmt_pending_free(cmd);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002262
2263unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002264 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002265 return err;
2266}
2267
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002268static int set_class_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002269{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002270 int err = 0;
Johan Hedberg92da6092013-03-15 17:06:55 -05002271
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002272 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
2273 cancel_delayed_work_sync(&hdev->service_cache);
2274 err = hci_update_eir_sync(hdev);
2275 }
2276
2277 if (err)
2278 return err;
2279
2280 return hci_update_class_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002281}
2282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002283static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002284 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002285{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002286 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002287 struct mgmt_pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002288 int err;
2289
Marcel Holtmann181d6952020-05-06 09:57:47 +02002290 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002291
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002292 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2294 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002295
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002296 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002297
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002298 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002299 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2300 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002301 goto unlock;
2302 }
2303
2304 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002305 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2306 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002307 goto unlock;
2308 }
2309
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002310 hdev->major_class = cp->major;
2311 hdev->minor_class = cp->minor;
2312
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002313 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002314 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2315 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002316 goto unlock;
2317 }
2318
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002319 cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002320 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002321 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002322 goto unlock;
2323 }
2324
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002325 err = hci_cmd_sync_queue(hdev, set_class_sync, cmd,
2326 mgmt_class_complete);
2327 if (err < 0)
2328 mgmt_pending_free(cmd);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002329
Johan Hedbergb5235a62012-02-21 14:32:24 +02002330unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002331 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002332 return err;
2333}
2334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002335static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002336 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002337{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002339 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2340 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002341 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002342 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002343 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
Marcel Holtmann181d6952020-05-06 09:57:47 +02002345 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002346
2347 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002348 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2349 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002350
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002351 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002352 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002353 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2354 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002355 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2356 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002357 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002359 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002360 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002361 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2362 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002363 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002365 }
2366
Johan Hedberg4ae143012013-01-20 14:27:13 +02002367 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002368 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2369 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002370
Marcel Holtmann181d6952020-05-06 09:57:47 +02002371 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2372 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002374 for (i = 0; i < key_count; i++) {
2375 struct mgmt_link_key_info *key = &cp->keys[i];
2376
Marcel Holtmann8e991132014-01-10 02:07:25 -08002377 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002378 return mgmt_cmd_status(sk, hdev->id,
2379 MGMT_OP_LOAD_LINK_KEYS,
2380 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002381 }
2382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002383 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002384
2385 hci_link_keys_clear(hdev);
2386
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002387 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002388 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002389 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002390 changed = hci_dev_test_and_clear_flag(hdev,
2391 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002392
2393 if (changed)
2394 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002395
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002396 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002397 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002398
Alain Michaud600a8742020-01-07 00:43:17 +00002399 if (hci_is_blocked_key(hdev,
2400 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2401 key->val)) {
2402 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2403 &key->addr.bdaddr);
2404 continue;
2405 }
2406
Johan Hedberg58e92932014-06-24 14:00:26 +03002407 /* Always ignore debug keys and require a new pairing if
2408 * the user wants to use them.
2409 */
2410 if (key->type == HCI_LK_DEBUG_COMBINATION)
2411 continue;
2412
Johan Hedberg7652ff62014-06-24 13:15:49 +03002413 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2414 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002415 }
2416
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002417 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002419 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002420
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002421 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002422}
2423
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002424static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002426{
2427 struct mgmt_ev_device_unpaired ev;
2428
2429 bacpy(&ev.addr.bdaddr, bdaddr);
2430 ev.addr.type = addr_type;
2431
2432 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002433 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002434}
2435
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002437 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002438{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002439 struct mgmt_cp_unpair_device *cp = data;
2440 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002441 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002442 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002443 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002444 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002445 int err;
2446
Johan Hedberga8a1d192011-11-10 15:54:38 +02002447 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002448 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2449 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002450
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002451 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002452 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2453 MGMT_STATUS_INVALID_PARAMS,
2454 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002455
Johan Hedberg118da702013-01-20 14:27:20 +02002456 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002457 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2458 MGMT_STATUS_INVALID_PARAMS,
2459 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002460
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002461 hci_dev_lock(hdev);
2462
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002463 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002464 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2465 MGMT_STATUS_NOT_POWERED, &rp,
2466 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002467 goto unlock;
2468 }
2469
Johan Hedberge0b2b272014-02-18 17:14:31 +02002470 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002471 /* If disconnection is requested, then look up the
2472 * connection. If the remote device is connected, it
2473 * will be later used to terminate the link.
2474 *
2475 * Setting it to NULL explicitly will cause no
2476 * termination of the link.
2477 */
2478 if (cp->disconnect)
2479 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2480 &cp->addr.bdaddr);
2481 else
2482 conn = NULL;
2483
Johan Hedberg124f6e32012-02-09 13:50:12 +02002484 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002485 if (err < 0) {
2486 err = mgmt_cmd_complete(sk, hdev->id,
2487 MGMT_OP_UNPAIR_DEVICE,
2488 MGMT_STATUS_NOT_PAIRED, &rp,
2489 sizeof(rp));
2490 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002491 }
2492
Johan Hedbergec182f02015-10-21 18:03:03 +03002493 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002494 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002495
Johan Hedbergec182f02015-10-21 18:03:03 +03002496 /* LE address type */
2497 addr_type = le_addr_type(cp->addr.type);
2498
Matias Karhumaacb28c302018-09-26 09:13:46 +03002499 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2500 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002501 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002502 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2503 MGMT_STATUS_NOT_PAIRED, &rp,
2504 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002505 goto unlock;
2506 }
2507
Johan Hedbergec182f02015-10-21 18:03:03 +03002508 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2509 if (!conn) {
2510 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2511 goto done;
2512 }
2513
Johan Hedbergc81d5552015-10-22 09:38:35 +03002514
Johan Hedbergec182f02015-10-21 18:03:03 +03002515 /* Defer clearing up the connection parameters until closing to
2516 * give a chance of keeping them if a repairing happens.
2517 */
2518 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2519
Johan Hedbergfc643612015-10-22 09:38:31 +03002520 /* Disable auto-connection parameters if present */
2521 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2522 if (params) {
2523 if (params->explicit_connect)
2524 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2525 else
2526 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2527 }
2528
Johan Hedbergec182f02015-10-21 18:03:03 +03002529 /* If disconnection is not requested, then clear the connection
2530 * variable so that the link is not terminated.
2531 */
2532 if (!cp->disconnect)
2533 conn = NULL;
2534
2535done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002536 /* If the connection variable is set, then termination of the
2537 * link is requested.
2538 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002539 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002540 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2541 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002542 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002543 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002544 }
2545
Johan Hedberg124f6e32012-02-09 13:50:12 +02002546 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002548 if (!cmd) {
2549 err = -ENOMEM;
2550 goto unlock;
2551 }
2552
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002553 cmd->cmd_complete = addr_cmd_complete;
2554
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002555 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002556 if (err < 0)
2557 mgmt_pending_remove(cmd);
2558
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002559unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002560 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002561 return err;
2562}
2563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002564static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002565 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002566{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002567 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002568 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002569 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002571 int err;
2572
Marcel Holtmann181d6952020-05-06 09:57:47 +02002573 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002574
Johan Hedberg06a63b12013-01-20 14:27:21 +02002575 memset(&rp, 0, sizeof(rp));
2576 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2577 rp.addr.type = cp->addr.type;
2578
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002579 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002580 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2581 MGMT_STATUS_INVALID_PARAMS,
2582 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002583
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002585
2586 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002587 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2588 MGMT_STATUS_NOT_POWERED, &rp,
2589 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002590 goto failed;
2591 }
2592
Johan Hedberg333ae952015-03-17 13:48:47 +02002593 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002594 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2595 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002596 goto failed;
2597 }
2598
Andre Guedes591f47f2012-04-24 21:02:49 -03002599 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002600 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2601 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002602 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002603 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2604 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002605
Vishal Agarwalf9607272012-06-13 05:32:43 +05302606 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002607 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2608 MGMT_STATUS_NOT_CONNECTED, &rp,
2609 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002610 goto failed;
2611 }
2612
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002613 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002614 if (!cmd) {
2615 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002616 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002617 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002618
Johan Hedbergf5818c22014-12-05 13:36:02 +02002619 cmd->cmd_complete = generic_cmd_complete;
2620
Johan Hedberge3f2f922014-08-18 20:33:33 +03002621 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002622 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002623 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002624
2625failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002626 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002627 return err;
2628}
2629
Andre Guedes57c14772012-04-24 21:02:50 -03002630static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002631{
2632 switch (link_type) {
2633 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002634 switch (addr_type) {
2635 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002636 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002637
Johan Hedberg48264f02011-11-09 13:58:58 +02002638 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002639 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002640 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002641 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002642
Johan Hedberg4c659c32011-11-07 23:13:39 +02002643 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002644 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002645 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002646 }
2647}
2648
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2650 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002651{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002652 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002653 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002654 int err;
2655 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002656
Marcel Holtmann181d6952020-05-06 09:57:47 +02002657 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002659 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002660
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002661 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002662 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2663 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002664 goto unlock;
2665 }
2666
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002667 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002668 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2669 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002670 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002671 }
2672
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002673 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002674 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002675 err = -ENOMEM;
2676 goto unlock;
2677 }
2678
Johan Hedberg2784eb42011-01-21 13:56:35 +02002679 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002680 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002681 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2682 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002683 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002684 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002685 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002686 continue;
2687 i++;
2688 }
2689
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002690 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002691
Johan Hedberg4c659c32011-11-07 23:13:39 +02002692 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002693 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002694 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002695
Johan Hedberga38528f2011-01-22 06:46:43 +02002696 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002697
2698unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002700 return err;
2701}
2702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002703static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002704 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002705{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002706 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002707 int err;
2708
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002709 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002710 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002711 if (!cmd)
2712 return -ENOMEM;
2713
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002714 cmd->cmd_complete = addr_cmd_complete;
2715
Johan Hedbergd8457692012-02-17 14:24:57 +02002716 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002718 if (err < 0)
2719 mgmt_pending_remove(cmd);
2720
2721 return err;
2722}
2723
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002724static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002725 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002727 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002728 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002729 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002730 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002731 int err;
2732
Marcel Holtmann181d6952020-05-06 09:57:47 +02002733 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002734
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002735 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002736
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002737 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002738 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2739 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002740 goto failed;
2741 }
2742
Johan Hedbergd8457692012-02-17 14:24:57 +02002743 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002744 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002745 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2746 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002747 goto failed;
2748 }
2749
2750 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002751 struct mgmt_cp_pin_code_neg_reply ncp;
2752
2753 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002754
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002755 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002757 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002758 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002759 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2760 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002761
2762 goto failed;
2763 }
2764
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002765 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002766 if (!cmd) {
2767 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002768 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002769 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002770
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002771 cmd->cmd_complete = addr_cmd_complete;
2772
Johan Hedbergd8457692012-02-17 14:24:57 +02002773 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002774 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002775 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002776
2777 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2778 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002779 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002780
2781failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002782 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002783 return err;
2784}
2785
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2787 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002788{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002789 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002790
Marcel Holtmann181d6952020-05-06 09:57:47 +02002791 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002792
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002793 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2795 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002797 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002798
2799 hdev->io_capability = cp->io_capability;
2800
Marcel Holtmann181d6952020-05-06 09:57:47 +02002801 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002802
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002803 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002804
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002805 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2806 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002807}
2808
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002809static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002810{
2811 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002812 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002813
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002814 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002815 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2816 continue;
2817
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818 if (cmd->user_data != conn)
2819 continue;
2820
2821 return cmd;
2822 }
2823
2824 return NULL;
2825}
2826
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002827static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002828{
2829 struct mgmt_rp_pair_device rp;
2830 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002831 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002832
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002833 bacpy(&rp.addr.bdaddr, &conn->dst);
2834 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002835
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002836 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2837 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002838
2839 /* So we don't get further callbacks for this connection */
2840 conn->connect_cfm_cb = NULL;
2841 conn->security_cfm_cb = NULL;
2842 conn->disconn_cfm_cb = NULL;
2843
David Herrmann76a68ba2013-04-06 20:28:37 +02002844 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002845
2846 /* The device is paired so there is no need to remove
2847 * its connection parameters anymore.
2848 */
2849 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002850
2851 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002852
2853 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002854}
2855
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002856void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2857{
2858 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002859 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002860
2861 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002862 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002863 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002864 mgmt_pending_remove(cmd);
2865 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002866}
2867
Johan Hedberge9a416b2011-02-19 12:05:56 -03002868static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002870 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002871
2872 BT_DBG("status %u", status);
2873
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002874 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002875 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002876 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002877 return;
2878 }
2879
2880 cmd->cmd_complete(cmd, mgmt_status(status));
2881 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002882}
2883
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002884static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302885{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002886 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302887
2888 BT_DBG("status %u", status);
2889
2890 if (!status)
2891 return;
2892
2893 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002894 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302895 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002896 return;
2897 }
2898
2899 cmd->cmd_complete(cmd, mgmt_status(status));
2900 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302901}
2902
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002903static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002905{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002906 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002907 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002908 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002909 u8 sec_level, auth_type;
2910 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002911 int err;
2912
Marcel Holtmann181d6952020-05-06 09:57:47 +02002913 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002914
Szymon Jancf950a30e2013-01-18 12:48:07 +01002915 memset(&rp, 0, sizeof(rp));
2916 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2917 rp.addr.type = cp->addr.type;
2918
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002919 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002920 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2921 MGMT_STATUS_INVALID_PARAMS,
2922 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002923
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002924 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002925 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2926 MGMT_STATUS_INVALID_PARAMS,
2927 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002928
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002929 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002930
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002931 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002932 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2933 MGMT_STATUS_NOT_POWERED, &rp,
2934 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002935 goto unlock;
2936 }
2937
Johan Hedberg55e76b32015-03-10 22:34:40 +02002938 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2939 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2940 MGMT_STATUS_ALREADY_PAIRED, &rp,
2941 sizeof(rp));
2942 goto unlock;
2943 }
2944
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002945 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002946 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002947
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002948 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002949 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002950 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002951 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002952 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002953 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002954
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002955 /* When pairing a new device, it is expected to remember
2956 * this device for future connections. Adding the connection
2957 * parameter information ahead of time allows tracking
Archie Pusaka67ffb182021-05-31 16:37:28 +08002958 * of the peripheral preferred values and will speed up any
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002959 * further connection establishment.
2960 *
2961 * If connection parameters already exist, then they
2962 * will be kept and this function does nothing.
2963 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002964 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2965
2966 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2967 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002968
Manish Mandlik76b13992020-06-17 16:39:19 +02002969 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2970 sec_level, HCI_LE_CONN_TIMEOUT,
2971 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002972 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002973
Ville Tervo30e76272011-02-22 16:10:53 -03002974 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002975 int status;
2976
2977 if (PTR_ERR(conn) == -EBUSY)
2978 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002979 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2980 status = MGMT_STATUS_NOT_SUPPORTED;
2981 else if (PTR_ERR(conn) == -ECONNREFUSED)
2982 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002983 else
2984 status = MGMT_STATUS_CONNECT_FAILED;
2985
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002986 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2987 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002988 goto unlock;
2989 }
2990
2991 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002992 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002993 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2994 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002995 goto unlock;
2996 }
2997
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002998 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002999 if (!cmd) {
3000 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003001 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003002 goto unlock;
3003 }
3004
Johan Hedberg04ab2742014-12-05 13:36:04 +02003005 cmd->cmd_complete = pairing_complete;
3006
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003007 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003008 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003009 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003010 conn->security_cfm_cb = pairing_complete_cb;
3011 conn->disconn_cfm_cb = pairing_complete_cb;
3012 } else {
3013 conn->connect_cfm_cb = le_pairing_complete_cb;
3014 conn->security_cfm_cb = le_pairing_complete_cb;
3015 conn->disconn_cfm_cb = le_pairing_complete_cb;
3016 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003017
Johan Hedberge9a416b2011-02-19 12:05:56 -03003018 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003019 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003020
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003021 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003022 hci_conn_security(conn, sec_level, auth_type, true)) {
3023 cmd->cmd_complete(cmd, 0);
3024 mgmt_pending_remove(cmd);
3025 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003026
3027 err = 0;
3028
3029unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003030 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003031 return err;
3032}
3033
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003034static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3035 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003036{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003037 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003038 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003039 struct hci_conn *conn;
3040 int err;
3041
Marcel Holtmann181d6952020-05-06 09:57:47 +02003042 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003043
Johan Hedberg28424702012-02-02 04:02:29 +02003044 hci_dev_lock(hdev);
3045
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003046 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003047 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3048 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003049 goto unlock;
3050 }
3051
Johan Hedberg333ae952015-03-17 13:48:47 +02003052 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003053 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003054 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3055 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003056 goto unlock;
3057 }
3058
3059 conn = cmd->user_data;
3060
3061 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003062 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3063 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003064 goto unlock;
3065 }
3066
Johan Hedberga511b352014-12-11 21:45:45 +02003067 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3068 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003069
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003070 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3071 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003072
3073 /* Since user doesn't want to proceed with the connection, abort any
3074 * ongoing pairing and then terminate the link if it was created
3075 * because of the pair device action.
3076 */
3077 if (addr->type == BDADDR_BREDR)
3078 hci_remove_link_key(hdev, &addr->bdaddr);
3079 else
3080 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3081 le_addr_type(addr->type));
3082
3083 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3084 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3085
Johan Hedberg28424702012-02-02 04:02:29 +02003086unlock:
3087 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003088 return err;
3089}
3090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003091static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003092 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003093 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003094{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003095 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003096 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003097 int err;
3098
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003099 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003100
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003101 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003102 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3103 MGMT_STATUS_NOT_POWERED, addr,
3104 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003105 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003106 }
3107
Johan Hedberg1707c602013-03-15 17:07:15 -05003108 if (addr->type == BDADDR_BREDR)
3109 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003110 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003111 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3112 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003113
Johan Hedberg272d90d2012-02-09 15:26:12 +02003114 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003115 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3116 MGMT_STATUS_NOT_CONNECTED, addr,
3117 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003118 goto done;
3119 }
3120
Johan Hedberg1707c602013-03-15 17:07:15 -05003121 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003122 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003123 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003124 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3125 MGMT_STATUS_SUCCESS, addr,
3126 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003127 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003128 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3129 MGMT_STATUS_FAILED, addr,
3130 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003131
Brian Gix47c15e22011-11-16 13:53:14 -08003132 goto done;
3133 }
3134
Johan Hedberg1707c602013-03-15 17:07:15 -05003135 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003136 if (!cmd) {
3137 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003138 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003139 }
3140
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003141 cmd->cmd_complete = addr_cmd_complete;
3142
Brian Gix0df4c182011-11-16 13:53:13 -08003143 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003144 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3145 struct hci_cp_user_passkey_reply cp;
3146
Johan Hedberg1707c602013-03-15 17:07:15 -05003147 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003148 cp.passkey = passkey;
3149 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3150 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003151 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3152 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003153
Johan Hedberga664b5b2011-02-19 12:06:02 -03003154 if (err < 0)
3155 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003156
Brian Gix0df4c182011-11-16 13:53:13 -08003157done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003158 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003159 return err;
3160}
3161
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303162static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3163 void *data, u16 len)
3164{
3165 struct mgmt_cp_pin_code_neg_reply *cp = data;
3166
Marcel Holtmann181d6952020-05-06 09:57:47 +02003167 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303168
Johan Hedberg1707c602013-03-15 17:07:15 -05003169 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303170 MGMT_OP_PIN_CODE_NEG_REPLY,
3171 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3172}
3173
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3175 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003176{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003177 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003178
Marcel Holtmann181d6952020-05-06 09:57:47 +02003179 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003180
3181 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003182 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3183 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003184
Johan Hedberg1707c602013-03-15 17:07:15 -05003185 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003186 MGMT_OP_USER_CONFIRM_REPLY,
3187 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003188}
3189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003190static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003192{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003193 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003194
Marcel Holtmann181d6952020-05-06 09:57:47 +02003195 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003196
Johan Hedberg1707c602013-03-15 17:07:15 -05003197 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3199 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003200}
3201
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003202static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3203 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003204{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003205 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003206
Marcel Holtmann181d6952020-05-06 09:57:47 +02003207 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003208
Johan Hedberg1707c602013-03-15 17:07:15 -05003209 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003210 MGMT_OP_USER_PASSKEY_REPLY,
3211 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003212}
3213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003214static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003215 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003216{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003217 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003218
Marcel Holtmann181d6952020-05-06 09:57:47 +02003219 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003220
Johan Hedberg1707c602013-03-15 17:07:15 -05003221 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003222 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3223 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003224}
3225
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003226static void adv_expire(struct hci_dev *hdev, u32 flags)
3227{
3228 struct adv_info *adv_instance;
3229 struct hci_request req;
3230 int err;
3231
3232 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3233 if (!adv_instance)
3234 return;
3235
3236 /* stop if current instance doesn't need to be changed */
3237 if (!(adv_instance->flags & flags))
3238 return;
3239
3240 cancel_adv_timeout(hdev);
3241
3242 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3243 if (!adv_instance)
3244 return;
3245
3246 hci_req_init(&req, hdev);
3247 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3248 true);
3249 if (err)
3250 return;
3251
3252 hci_req_run(&req, NULL);
3253}
3254
Marcel Holtmann1904a852015-01-11 13:50:44 -08003255static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003256{
3257 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003258 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003259
Marcel Holtmann181d6952020-05-06 09:57:47 +02003260 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003261
3262 hci_dev_lock(hdev);
3263
Johan Hedberg333ae952015-03-17 13:48:47 +02003264 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003265 if (!cmd)
3266 goto unlock;
3267
3268 cp = cmd->param;
3269
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003270 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003271 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3272 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003273 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003274 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3275 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003276
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003277 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3278 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3279 }
3280
Johan Hedberg13928972013-03-15 17:07:00 -05003281 mgmt_pending_remove(cmd);
3282
3283unlock:
3284 hci_dev_unlock(hdev);
3285}
3286
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003287static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003288 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003289{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003290 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003291 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003292 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003293 int err;
3294
Marcel Holtmann181d6952020-05-06 09:57:47 +02003295 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003296
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003297 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003298
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003299 /* If the old values are the same as the new ones just return a
3300 * direct command complete event.
3301 */
3302 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3303 !memcmp(hdev->short_name, cp->short_name,
3304 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003305 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3306 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003307 goto failed;
3308 }
3309
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003310 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003311
Johan Hedbergb5235a62012-02-21 14:32:24 +02003312 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003313 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003314
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003315 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3316 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003317 if (err < 0)
3318 goto failed;
3319
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003320 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3321 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003322 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003323
Johan Hedbergb5235a62012-02-21 14:32:24 +02003324 goto failed;
3325 }
3326
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003327 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003328 if (!cmd) {
3329 err = -ENOMEM;
3330 goto failed;
3331 }
3332
Johan Hedberg13928972013-03-15 17:07:00 -05003333 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3334
Johan Hedberg890ea892013-03-15 17:06:52 -05003335 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003336
3337 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003338 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003339 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003340 }
3341
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003342 /* The name is stored in the scan response data and so
Zheng Yongjun91641b72021-06-02 14:54:58 +08003343 * no need to update the advertising data here.
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003344 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003345 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003346 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003347
Johan Hedberg13928972013-03-15 17:07:00 -05003348 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003349 if (err < 0)
3350 mgmt_pending_remove(cmd);
3351
3352failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003353 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003354 return err;
3355}
3356
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003357static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3358 u16 len)
3359{
3360 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003361 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003362 int err;
3363
Marcel Holtmann181d6952020-05-06 09:57:47 +02003364 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003365
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003366 if (!lmp_le_capable(hdev))
3367 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3368 MGMT_STATUS_NOT_SUPPORTED);
3369
Alain Michaud6613bab2020-01-22 19:47:44 +00003370 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003371
3372 hci_dev_lock(hdev);
3373
Alain Michaud6613bab2020-01-22 19:47:44 +00003374 if (hdev->appearance != appearance) {
3375 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003376
3377 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3378 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003379
3380 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003381 }
3382
3383 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3384 0);
3385
3386 hci_dev_unlock(hdev);
3387
3388 return err;
3389}
3390
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303391static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3392 void *data, u16 len)
3393{
Reo Shiseki353021582020-11-19 16:37:11 +09003394 struct mgmt_rp_get_phy_configuration rp;
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303395
Marcel Holtmann181d6952020-05-06 09:57:47 +02003396 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303397
3398 hci_dev_lock(hdev);
3399
3400 memset(&rp, 0, sizeof(rp));
3401
3402 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3403 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3404 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3405
3406 hci_dev_unlock(hdev);
3407
3408 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3409 &rp, sizeof(rp));
3410}
3411
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303412int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3413{
3414 struct mgmt_ev_phy_configuration_changed ev;
3415
3416 memset(&ev, 0, sizeof(ev));
3417
3418 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3419
3420 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3421 sizeof(ev), skip);
3422}
3423
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303424static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3425 u16 opcode, struct sk_buff *skb)
3426{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303427 struct mgmt_pending_cmd *cmd;
3428
Marcel Holtmann181d6952020-05-06 09:57:47 +02003429 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303430
3431 hci_dev_lock(hdev);
3432
3433 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3434 if (!cmd)
3435 goto unlock;
3436
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303437 if (status) {
3438 mgmt_cmd_status(cmd->sk, hdev->id,
3439 MGMT_OP_SET_PHY_CONFIGURATION,
3440 mgmt_status(status));
3441 } else {
3442 mgmt_cmd_complete(cmd->sk, hdev->id,
3443 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3444 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303445
3446 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303447 }
3448
3449 mgmt_pending_remove(cmd);
3450
3451unlock:
3452 hci_dev_unlock(hdev);
3453}
3454
3455static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3456 void *data, u16 len)
3457{
Reo Shiseki353021582020-11-19 16:37:11 +09003458 struct mgmt_cp_set_phy_configuration *cp = data;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303459 struct hci_cp_le_set_default_phy cp_phy;
3460 struct mgmt_pending_cmd *cmd;
3461 struct hci_request req;
3462 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3463 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303464 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303465 int err;
3466
Marcel Holtmann181d6952020-05-06 09:57:47 +02003467 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303468
3469 configurable_phys = get_configurable_phys(hdev);
3470 supported_phys = get_supported_phys(hdev);
3471 selected_phys = __le32_to_cpu(cp->selected_phys);
3472
3473 if (selected_phys & ~supported_phys)
3474 return mgmt_cmd_status(sk, hdev->id,
3475 MGMT_OP_SET_PHY_CONFIGURATION,
3476 MGMT_STATUS_INVALID_PARAMS);
3477
3478 unconfigure_phys = supported_phys & ~configurable_phys;
3479
3480 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3481 return mgmt_cmd_status(sk, hdev->id,
3482 MGMT_OP_SET_PHY_CONFIGURATION,
3483 MGMT_STATUS_INVALID_PARAMS);
3484
3485 if (selected_phys == get_selected_phys(hdev))
3486 return mgmt_cmd_complete(sk, hdev->id,
3487 MGMT_OP_SET_PHY_CONFIGURATION,
3488 0, NULL, 0);
3489
3490 hci_dev_lock(hdev);
3491
3492 if (!hdev_is_powered(hdev)) {
3493 err = mgmt_cmd_status(sk, hdev->id,
3494 MGMT_OP_SET_PHY_CONFIGURATION,
3495 MGMT_STATUS_REJECTED);
3496 goto unlock;
3497 }
3498
3499 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3500 err = mgmt_cmd_status(sk, hdev->id,
3501 MGMT_OP_SET_PHY_CONFIGURATION,
3502 MGMT_STATUS_BUSY);
3503 goto unlock;
3504 }
3505
3506 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3507 pkt_type |= (HCI_DH3 | HCI_DM3);
3508 else
3509 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3510
3511 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3512 pkt_type |= (HCI_DH5 | HCI_DM5);
3513 else
3514 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3515
3516 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3517 pkt_type &= ~HCI_2DH1;
3518 else
3519 pkt_type |= HCI_2DH1;
3520
3521 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3522 pkt_type &= ~HCI_2DH3;
3523 else
3524 pkt_type |= HCI_2DH3;
3525
3526 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3527 pkt_type &= ~HCI_2DH5;
3528 else
3529 pkt_type |= HCI_2DH5;
3530
3531 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3532 pkt_type &= ~HCI_3DH1;
3533 else
3534 pkt_type |= HCI_3DH1;
3535
3536 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3537 pkt_type &= ~HCI_3DH3;
3538 else
3539 pkt_type |= HCI_3DH3;
3540
3541 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3542 pkt_type &= ~HCI_3DH5;
3543 else
3544 pkt_type |= HCI_3DH5;
3545
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303546 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303547 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303548 changed = true;
3549 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303550
3551 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3552 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303553 if (changed)
3554 mgmt_phy_configuration_changed(hdev, sk);
3555
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303556 err = mgmt_cmd_complete(sk, hdev->id,
3557 MGMT_OP_SET_PHY_CONFIGURATION,
3558 0, NULL, 0);
3559
3560 goto unlock;
3561 }
3562
3563 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3564 len);
3565 if (!cmd) {
3566 err = -ENOMEM;
3567 goto unlock;
3568 }
3569
3570 hci_req_init(&req, hdev);
3571
3572 memset(&cp_phy, 0, sizeof(cp_phy));
3573
3574 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3575 cp_phy.all_phys |= 0x01;
3576
3577 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3578 cp_phy.all_phys |= 0x02;
3579
3580 if (selected_phys & MGMT_PHY_LE_1M_TX)
3581 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3582
3583 if (selected_phys & MGMT_PHY_LE_2M_TX)
3584 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3585
3586 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3587 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3588
3589 if (selected_phys & MGMT_PHY_LE_1M_RX)
3590 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3591
3592 if (selected_phys & MGMT_PHY_LE_2M_RX)
3593 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3594
3595 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3596 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3597
3598 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3599
3600 err = hci_req_run_skb(&req, set_default_phy_complete);
3601 if (err < 0)
3602 mgmt_pending_remove(cmd);
3603
3604unlock:
3605 hci_dev_unlock(hdev);
3606
3607 return err;
3608}
3609
Alain Michaud600a8742020-01-07 00:43:17 +00003610static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3611 u16 len)
3612{
3613 int err = MGMT_STATUS_SUCCESS;
3614 struct mgmt_cp_set_blocked_keys *keys = data;
3615 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3616 sizeof(struct mgmt_blocked_key_info));
3617 u16 key_count, expected_len;
3618 int i;
3619
Marcel Holtmann181d6952020-05-06 09:57:47 +02003620 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003621
3622 key_count = __le16_to_cpu(keys->key_count);
3623 if (key_count > max_key_count) {
3624 bt_dev_err(hdev, "too big key_count value %u", key_count);
3625 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3626 MGMT_STATUS_INVALID_PARAMS);
3627 }
3628
3629 expected_len = struct_size(keys, keys, key_count);
3630 if (expected_len != len) {
3631 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3632 expected_len, len);
3633 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3634 MGMT_STATUS_INVALID_PARAMS);
3635 }
3636
3637 hci_dev_lock(hdev);
3638
3639 hci_blocked_keys_clear(hdev);
3640
3641 for (i = 0; i < keys->key_count; ++i) {
3642 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3643
3644 if (!b) {
3645 err = MGMT_STATUS_NO_RESOURCES;
3646 break;
3647 }
3648
3649 b->type = keys->keys[i].type;
3650 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3651 list_add_rcu(&b->list, &hdev->blocked_keys);
3652 }
3653 hci_dev_unlock(hdev);
3654
3655 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3656 err, NULL, 0);
3657}
3658
Alain Michaud00bce3f2020-03-05 16:14:59 +00003659static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3660 void *data, u16 len)
3661{
3662 struct mgmt_mode *cp = data;
3663 int err;
3664 bool changed = false;
3665
Marcel Holtmann181d6952020-05-06 09:57:47 +02003666 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003667
3668 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3669 return mgmt_cmd_status(sk, hdev->id,
3670 MGMT_OP_SET_WIDEBAND_SPEECH,
3671 MGMT_STATUS_NOT_SUPPORTED);
3672
3673 if (cp->val != 0x00 && cp->val != 0x01)
3674 return mgmt_cmd_status(sk, hdev->id,
3675 MGMT_OP_SET_WIDEBAND_SPEECH,
3676 MGMT_STATUS_INVALID_PARAMS);
3677
3678 hci_dev_lock(hdev);
3679
3680 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3681 err = mgmt_cmd_status(sk, hdev->id,
3682 MGMT_OP_SET_WIDEBAND_SPEECH,
3683 MGMT_STATUS_BUSY);
3684 goto unlock;
3685 }
3686
3687 if (hdev_is_powered(hdev) &&
3688 !!cp->val != hci_dev_test_flag(hdev,
3689 HCI_WIDEBAND_SPEECH_ENABLED)) {
3690 err = mgmt_cmd_status(sk, hdev->id,
3691 MGMT_OP_SET_WIDEBAND_SPEECH,
3692 MGMT_STATUS_REJECTED);
3693 goto unlock;
3694 }
3695
3696 if (cp->val)
3697 changed = !hci_dev_test_and_set_flag(hdev,
3698 HCI_WIDEBAND_SPEECH_ENABLED);
3699 else
3700 changed = hci_dev_test_and_clear_flag(hdev,
3701 HCI_WIDEBAND_SPEECH_ENABLED);
3702
3703 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3704 if (err < 0)
3705 goto unlock;
3706
3707 if (changed)
3708 err = new_settings(hdev, sk);
3709
3710unlock:
3711 hci_dev_unlock(hdev);
3712 return err;
3713}
3714
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003715static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
3716 void *data, u16 data_len)
Marcel Holtmannbc292252020-04-03 21:44:05 +02003717{
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003718 char buf[20];
3719 struct mgmt_rp_read_controller_cap *rp = (void *)buf;
3720 u16 cap_len = 0;
Marcel Holtmannbc292252020-04-03 21:44:05 +02003721 u8 flags = 0;
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003722 u8 tx_power_range[2];
Marcel Holtmannbc292252020-04-03 21:44:05 +02003723
3724 bt_dev_dbg(hdev, "sock %p", sk);
3725
3726 memset(&buf, 0, sizeof(buf));
3727
3728 hci_dev_lock(hdev);
3729
3730 /* When the Read Simple Pairing Options command is supported, then
3731 * the remote public key validation is supported.
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003732 *
3733 * Alternatively, when Microsoft extensions are available, they can
3734 * indicate support for public key validation as well.
Marcel Holtmannbc292252020-04-03 21:44:05 +02003735 */
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003736 if ((hdev->commands[41] & 0x08) || msft_curve_validity(hdev))
Marcel Holtmannbc292252020-04-03 21:44:05 +02003737 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3738
3739 flags |= 0x02; /* Remote public key validation (LE) */
3740
3741 /* When the Read Encryption Key Size command is supported, then the
3742 * encryption key size is enforced.
3743 */
3744 if (hdev->commands[20] & 0x10)
3745 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3746
3747 flags |= 0x08; /* Encryption key size enforcement (LE) */
3748
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003749 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS,
3750 &flags, 1);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003751
3752 /* When the Read Simple Pairing Options command is supported, then
3753 * also max encryption key size information is provided.
3754 */
3755 if (hdev->commands[41] & 0x08)
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003756 cap_len = eir_append_le16(rp->cap, cap_len,
3757 MGMT_CAP_MAX_ENC_KEY_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02003758 hdev->max_enc_key_size);
3759
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003760 cap_len = eir_append_le16(rp->cap, cap_len,
3761 MGMT_CAP_SMP_MAX_ENC_KEY_SIZE,
3762 SMP_MAX_ENC_KEY_SIZE);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003763
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003764 /* Append the min/max LE tx power parameters if we were able to fetch
3765 * it from the controller
3766 */
3767 if (hdev->commands[38] & 0x80) {
3768 memcpy(&tx_power_range[0], &hdev->min_le_tx_power, 1);
3769 memcpy(&tx_power_range[1], &hdev->max_le_tx_power, 1);
3770 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR,
3771 tx_power_range, 2);
3772 }
3773
3774 rp->cap_len = cpu_to_le16(cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003775
3776 hci_dev_unlock(hdev);
3777
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003778 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0,
3779 rp, sizeof(*rp) + cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003780}
3781
Marcel Holtmanne625e502020-05-06 09:57:52 +02003782#ifdef CONFIG_BT_FEATURE_DEBUG
3783/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3784static const u8 debug_uuid[16] = {
3785 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3786 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3787};
3788#endif
3789
Joseph Hwangae7d9252021-08-15 20:17:16 +08003790/* 330859bc-7506-492d-9370-9a6f0614037f */
3791static const u8 quality_report_uuid[16] = {
3792 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
3793 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
3794};
3795
Kiran Kad933152021-09-07 15:42:47 +05303796/* a6695ace-ee7f-4fb9-881a-5fac66c629af */
3797static const u8 offload_codecs_uuid[16] = {
3798 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88,
3799 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6,
3800};
3801
Alain Michaud15d8ce02020-07-07 17:46:06 +02003802/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3803static const u8 simult_central_periph_uuid[16] = {
3804 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3805 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3806};
3807
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303808/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3809static const u8 rpa_resolution_uuid[16] = {
3810 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3811 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3812};
3813
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003814static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3815 void *data, u16 data_len)
3816{
Kiran Kad933152021-09-07 15:42:47 +05303817 char buf[102]; /* Enough space for 5 features: 2 + 20 * 5 */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003818 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3819 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003820 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003821
3822 bt_dev_dbg(hdev, "sock %p", sk);
3823
3824 memset(&buf, 0, sizeof(buf));
3825
Marcel Holtmanne625e502020-05-06 09:57:52 +02003826#ifdef CONFIG_BT_FEATURE_DEBUG
3827 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003828 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003829
3830 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3831 rp->features[idx].flags = cpu_to_le32(flags);
3832 idx++;
3833 }
3834#endif
3835
Alain Michaud15d8ce02020-07-07 17:46:06 +02003836 if (hdev) {
3837 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3838 (hdev->le_states[4] & 0x08) && /* Central */
3839 (hdev->le_states[4] & 0x40) && /* Peripheral */
3840 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3841 flags = BIT(0);
3842 else
3843 flags = 0;
3844
3845 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3846 rp->features[idx].flags = cpu_to_le32(flags);
3847 idx++;
3848 }
3849
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07003850 if (hdev && ll_privacy_capable(hdev)) {
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303851 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3852 flags = BIT(0) | BIT(1);
3853 else
3854 flags = BIT(1);
3855
3856 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3857 rp->features[idx].flags = cpu_to_le32(flags);
3858 idx++;
3859 }
3860
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003861 if (hdev && hdev->set_quality_report) {
3862 if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
Joseph Hwangae7d9252021-08-15 20:17:16 +08003863 flags = BIT(0);
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003864 else
Joseph Hwangae7d9252021-08-15 20:17:16 +08003865 flags = 0;
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003866
Joseph Hwangae7d9252021-08-15 20:17:16 +08003867 memcpy(rp->features[idx].uuid, quality_report_uuid, 16);
3868 rp->features[idx].flags = cpu_to_le32(flags);
3869 idx++;
3870 }
3871
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003872 if (hdev && hdev->get_data_path_id) {
3873 if (hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED))
Kiran Kad933152021-09-07 15:42:47 +05303874 flags = BIT(0);
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003875 else
Kiran Kad933152021-09-07 15:42:47 +05303876 flags = 0;
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003877
Kiran Kad933152021-09-07 15:42:47 +05303878 memcpy(rp->features[idx].uuid, offload_codecs_uuid, 16);
3879 rp->features[idx].flags = cpu_to_le32(flags);
3880 idx++;
3881 }
3882
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003883 rp->feature_count = cpu_to_le16(idx);
3884
3885 /* After reading the experimental features information, enable
3886 * the events to update client on any future change.
3887 */
3888 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3889
3890 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3891 MGMT_OP_READ_EXP_FEATURES_INFO,
3892 0, rp, sizeof(*rp) + (20 * idx));
3893}
3894
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303895static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3896 struct sock *skip)
3897{
3898 struct mgmt_ev_exp_feature_changed ev;
3899
3900 memset(&ev, 0, sizeof(ev));
3901 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3902 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3903
3904 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3905 &ev, sizeof(ev),
3906 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3907
3908}
3909
Marcel Holtmanne625e502020-05-06 09:57:52 +02003910#ifdef CONFIG_BT_FEATURE_DEBUG
3911static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3912{
3913 struct mgmt_ev_exp_feature_changed ev;
3914
3915 memset(&ev, 0, sizeof(ev));
3916 memcpy(ev.uuid, debug_uuid, 16);
3917 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3918
3919 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3920 &ev, sizeof(ev),
3921 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3922}
3923#endif
3924
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07003925static int exp_quality_report_feature_changed(bool enabled,
3926 struct hci_dev *hdev,
3927 struct sock *skip)
Joseph Hwangae7d9252021-08-15 20:17:16 +08003928{
3929 struct mgmt_ev_exp_feature_changed ev;
3930
3931 memset(&ev, 0, sizeof(ev));
3932 memcpy(ev.uuid, quality_report_uuid, 16);
3933 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3934
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07003935 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
Joseph Hwangae7d9252021-08-15 20:17:16 +08003936 &ev, sizeof(ev),
3937 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3938}
3939
Joseph Hwang93fb70b2021-08-15 20:17:15 +08003940#define EXP_FEAT(_uuid, _set_func) \
3941{ \
3942 .uuid = _uuid, \
3943 .set_func = _set_func, \
3944}
3945
3946/* The zero key uuid is special. Multiple exp features are set through it. */
3947static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
3948 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
3949{
3950 struct mgmt_rp_set_exp_feature rp;
3951
3952 memset(rp.uuid, 0, 16);
3953 rp.flags = cpu_to_le32(0);
3954
3955#ifdef CONFIG_BT_FEATURE_DEBUG
3956 if (!hdev) {
3957 bool changed = bt_dbg_get();
3958
3959 bt_dbg_set(false);
3960
3961 if (changed)
3962 exp_debug_feature_changed(false, sk);
3963 }
3964#endif
3965
3966 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3967 bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3968
3969 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3970
3971 if (changed)
3972 exp_ll_privacy_feature_changed(false, hdev, sk);
3973 }
3974
3975 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3976
3977 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3978 MGMT_OP_SET_EXP_FEATURE, 0,
3979 &rp, sizeof(rp));
3980}
3981
3982#ifdef CONFIG_BT_FEATURE_DEBUG
3983static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
3984 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
3985{
3986 struct mgmt_rp_set_exp_feature rp;
3987
3988 bool val, changed;
3989 int err;
3990
3991 /* Command requires to use the non-controller index */
3992 if (hdev)
3993 return mgmt_cmd_status(sk, hdev->id,
3994 MGMT_OP_SET_EXP_FEATURE,
3995 MGMT_STATUS_INVALID_INDEX);
3996
3997 /* Parameters are limited to a single octet */
3998 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3999 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4000 MGMT_OP_SET_EXP_FEATURE,
4001 MGMT_STATUS_INVALID_PARAMS);
4002
4003 /* Only boolean on/off is supported */
4004 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4005 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4006 MGMT_OP_SET_EXP_FEATURE,
4007 MGMT_STATUS_INVALID_PARAMS);
4008
4009 val = !!cp->param[0];
4010 changed = val ? !bt_dbg_get() : bt_dbg_get();
4011 bt_dbg_set(val);
4012
4013 memcpy(rp.uuid, debug_uuid, 16);
4014 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4015
4016 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4017
4018 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
4019 MGMT_OP_SET_EXP_FEATURE, 0,
4020 &rp, sizeof(rp));
4021
4022 if (changed)
4023 exp_debug_feature_changed(val, sk);
4024
4025 return err;
4026}
4027#endif
4028
4029static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
4030 struct mgmt_cp_set_exp_feature *cp,
4031 u16 data_len)
4032{
4033 struct mgmt_rp_set_exp_feature rp;
4034 bool val, changed;
4035 int err;
4036 u32 flags;
4037
4038 /* Command requires to use the controller index */
4039 if (!hdev)
4040 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4041 MGMT_OP_SET_EXP_FEATURE,
4042 MGMT_STATUS_INVALID_INDEX);
4043
4044 /* Changes can only be made when controller is powered down */
4045 if (hdev_is_powered(hdev))
4046 return mgmt_cmd_status(sk, hdev->id,
4047 MGMT_OP_SET_EXP_FEATURE,
4048 MGMT_STATUS_REJECTED);
4049
4050 /* Parameters are limited to a single octet */
4051 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4052 return mgmt_cmd_status(sk, hdev->id,
4053 MGMT_OP_SET_EXP_FEATURE,
4054 MGMT_STATUS_INVALID_PARAMS);
4055
4056 /* Only boolean on/off is supported */
4057 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4058 return mgmt_cmd_status(sk, hdev->id,
4059 MGMT_OP_SET_EXP_FEATURE,
4060 MGMT_STATUS_INVALID_PARAMS);
4061
4062 val = !!cp->param[0];
4063
4064 if (val) {
4065 changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4066 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4067 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
4068
4069 /* Enable LL privacy + supported settings changed */
4070 flags = BIT(0) | BIT(1);
4071 } else {
4072 changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4073 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4074
4075 /* Disable LL privacy + supported settings changed */
4076 flags = BIT(1);
4077 }
4078
4079 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4080 rp.flags = cpu_to_le32(flags);
4081
4082 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4083
4084 err = mgmt_cmd_complete(sk, hdev->id,
4085 MGMT_OP_SET_EXP_FEATURE, 0,
4086 &rp, sizeof(rp));
4087
4088 if (changed)
4089 exp_ll_privacy_feature_changed(val, hdev, sk);
4090
4091 return err;
4092}
4093
Joseph Hwangae7d9252021-08-15 20:17:16 +08004094static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
4095 struct mgmt_cp_set_exp_feature *cp,
4096 u16 data_len)
4097{
4098 struct mgmt_rp_set_exp_feature rp;
4099 bool val, changed;
4100 int err;
4101
4102 /* Command requires to use a valid controller index */
4103 if (!hdev)
4104 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4105 MGMT_OP_SET_EXP_FEATURE,
4106 MGMT_STATUS_INVALID_INDEX);
4107
4108 /* Parameters are limited to a single octet */
4109 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4110 return mgmt_cmd_status(sk, hdev->id,
4111 MGMT_OP_SET_EXP_FEATURE,
4112 MGMT_STATUS_INVALID_PARAMS);
4113
4114 /* Only boolean on/off is supported */
4115 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4116 return mgmt_cmd_status(sk, hdev->id,
4117 MGMT_OP_SET_EXP_FEATURE,
4118 MGMT_STATUS_INVALID_PARAMS);
4119
4120 hci_req_sync_lock(hdev);
4121
4122 val = !!cp->param[0];
4123 changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
4124
4125 if (!hdev->set_quality_report) {
4126 err = mgmt_cmd_status(sk, hdev->id,
4127 MGMT_OP_SET_EXP_FEATURE,
4128 MGMT_STATUS_NOT_SUPPORTED);
4129 goto unlock_quality_report;
4130 }
4131
4132 if (changed) {
4133 err = hdev->set_quality_report(hdev, val);
4134 if (err) {
4135 err = mgmt_cmd_status(sk, hdev->id,
4136 MGMT_OP_SET_EXP_FEATURE,
4137 MGMT_STATUS_FAILED);
4138 goto unlock_quality_report;
4139 }
4140 if (val)
4141 hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
4142 else
4143 hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
4144 }
4145
4146 bt_dev_dbg(hdev, "quality report enable %d changed %d", val, changed);
4147
4148 memcpy(rp.uuid, quality_report_uuid, 16);
4149 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4150 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4151 err = mgmt_cmd_complete(sk, hdev->id,
4152 MGMT_OP_SET_EXP_FEATURE, 0,
4153 &rp, sizeof(rp));
4154
4155 if (changed)
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004156 exp_quality_report_feature_changed(val, hdev, sk);
Joseph Hwangae7d9252021-08-15 20:17:16 +08004157
4158unlock_quality_report:
4159 hci_req_sync_unlock(hdev);
4160 return err;
4161}
4162
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004163static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
4164 struct sock *skip)
Kiran Kad933152021-09-07 15:42:47 +05304165{
4166 struct mgmt_ev_exp_feature_changed ev;
4167
4168 memset(&ev, 0, sizeof(ev));
4169 memcpy(ev.uuid, offload_codecs_uuid, 16);
4170 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4171
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004172 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
Kiran Kad933152021-09-07 15:42:47 +05304173 &ev, sizeof(ev),
4174 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4175}
4176
4177static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
4178 struct mgmt_cp_set_exp_feature *cp,
4179 u16 data_len)
4180{
4181 bool val, changed;
4182 int err;
4183 struct mgmt_rp_set_exp_feature rp;
4184
4185 /* Command requires to use a valid controller index */
4186 if (!hdev)
4187 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4188 MGMT_OP_SET_EXP_FEATURE,
4189 MGMT_STATUS_INVALID_INDEX);
4190
4191 /* Parameters are limited to a single octet */
4192 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4193 return mgmt_cmd_status(sk, hdev->id,
4194 MGMT_OP_SET_EXP_FEATURE,
4195 MGMT_STATUS_INVALID_PARAMS);
4196
4197 /* Only boolean on/off is supported */
4198 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4199 return mgmt_cmd_status(sk, hdev->id,
4200 MGMT_OP_SET_EXP_FEATURE,
4201 MGMT_STATUS_INVALID_PARAMS);
4202
4203 val = !!cp->param[0];
4204 changed = (val != hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED));
4205
4206 if (!hdev->get_data_path_id) {
4207 return mgmt_cmd_status(sk, hdev->id,
4208 MGMT_OP_SET_EXP_FEATURE,
4209 MGMT_STATUS_NOT_SUPPORTED);
4210 }
4211
4212 if (changed) {
4213 if (val)
4214 hci_dev_set_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4215 else
4216 hci_dev_clear_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4217 }
4218
4219 bt_dev_info(hdev, "offload codecs enable %d changed %d",
4220 val, changed);
4221
4222 memcpy(rp.uuid, offload_codecs_uuid, 16);
4223 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4224 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4225 err = mgmt_cmd_complete(sk, hdev->id,
4226 MGMT_OP_SET_EXP_FEATURE, 0,
4227 &rp, sizeof(rp));
4228
4229 if (changed)
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004230 exp_offload_codec_feature_changed(val, hdev, sk);
Kiran Kad933152021-09-07 15:42:47 +05304231
4232 return err;
4233}
4234
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004235static const struct mgmt_exp_feature {
4236 const u8 *uuid;
4237 int (*set_func)(struct sock *sk, struct hci_dev *hdev,
4238 struct mgmt_cp_set_exp_feature *cp, u16 data_len);
4239} exp_features[] = {
4240 EXP_FEAT(ZERO_KEY, set_zero_key_func),
4241#ifdef CONFIG_BT_FEATURE_DEBUG
4242 EXP_FEAT(debug_uuid, set_debug_func),
4243#endif
4244 EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
Joseph Hwangae7d9252021-08-15 20:17:16 +08004245 EXP_FEAT(quality_report_uuid, set_quality_report_func),
Kiran Kad933152021-09-07 15:42:47 +05304246 EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004247
4248 /* end with a null feature */
4249 EXP_FEAT(NULL, NULL)
4250};
4251
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004252static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
4253 void *data, u16 data_len)
4254{
4255 struct mgmt_cp_set_exp_feature *cp = data;
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004256 size_t i = 0;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004257
4258 bt_dev_dbg(hdev, "sock %p", sk);
4259
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004260 for (i = 0; exp_features[i].uuid; i++) {
4261 if (!memcmp(cp->uuid, exp_features[i].uuid, 16))
4262 return exp_features[i].set_func(sk, hdev, cp, data_len);
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05304263 }
4264
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004265 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4266 MGMT_OP_SET_EXP_FEATURE,
4267 MGMT_STATUS_NOT_SUPPORTED);
4268}
4269
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004270#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4271
4272static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4273 u16 data_len)
4274{
4275 struct mgmt_cp_get_device_flags *cp = data;
4276 struct mgmt_rp_get_device_flags rp;
4277 struct bdaddr_list_with_flags *br_params;
4278 struct hci_conn_params *params;
4279 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4280 u32 current_flags = 0;
4281 u8 status = MGMT_STATUS_INVALID_PARAMS;
4282
4283 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4284 &cp->addr.bdaddr, cp->addr.type);
4285
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004286 hci_dev_lock(hdev);
4287
Tedd Ho-Jeong An02ce2c22021-05-26 10:36:22 -07004288 memset(&rp, 0, sizeof(rp));
4289
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004290 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004291 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004292 &cp->addr.bdaddr,
4293 cp->addr.type);
4294 if (!br_params)
4295 goto done;
4296
4297 current_flags = br_params->current_flags;
4298 } else {
4299 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4300 le_addr_type(cp->addr.type));
4301
4302 if (!params)
4303 goto done;
4304
4305 current_flags = params->current_flags;
4306 }
4307
4308 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4309 rp.addr.type = cp->addr.type;
4310 rp.supported_flags = cpu_to_le32(supported_flags);
4311 rp.current_flags = cpu_to_le32(current_flags);
4312
4313 status = MGMT_STATUS_SUCCESS;
4314
4315done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004316 hci_dev_unlock(hdev);
4317
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004318 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4319 &rp, sizeof(rp));
4320}
4321
4322static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4323 bdaddr_t *bdaddr, u8 bdaddr_type,
4324 u32 supported_flags, u32 current_flags)
4325{
4326 struct mgmt_ev_device_flags_changed ev;
4327
4328 bacpy(&ev.addr.bdaddr, bdaddr);
4329 ev.addr.type = bdaddr_type;
4330 ev.supported_flags = cpu_to_le32(supported_flags);
4331 ev.current_flags = cpu_to_le32(current_flags);
4332
4333 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4334}
4335
4336static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4337 u16 len)
4338{
4339 struct mgmt_cp_set_device_flags *cp = data;
4340 struct bdaddr_list_with_flags *br_params;
4341 struct hci_conn_params *params;
4342 u8 status = MGMT_STATUS_INVALID_PARAMS;
4343 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4344 u32 current_flags = __le32_to_cpu(cp->current_flags);
4345
4346 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4347 &cp->addr.bdaddr, cp->addr.type,
4348 __le32_to_cpu(current_flags));
4349
4350 if ((supported_flags | current_flags) != supported_flags) {
4351 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4352 current_flags, supported_flags);
4353 goto done;
4354 }
4355
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004356 hci_dev_lock(hdev);
4357
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004358 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004359 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004360 &cp->addr.bdaddr,
4361 cp->addr.type);
4362
4363 if (br_params) {
4364 br_params->current_flags = current_flags;
4365 status = MGMT_STATUS_SUCCESS;
4366 } else {
4367 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4368 &cp->addr.bdaddr, cp->addr.type);
4369 }
4370 } else {
4371 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4372 le_addr_type(cp->addr.type));
4373 if (params) {
4374 params->current_flags = current_flags;
4375 status = MGMT_STATUS_SUCCESS;
4376 } else {
4377 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4378 &cp->addr.bdaddr,
4379 le_addr_type(cp->addr.type));
4380 }
4381 }
4382
4383done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004384 hci_dev_unlock(hdev);
4385
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004386 if (status == MGMT_STATUS_SUCCESS)
4387 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4388 supported_flags, current_flags);
4389
4390 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4391 &cp->addr, sizeof(cp->addr));
4392}
4393
Miao-chen Choub52729f2020-06-17 16:39:16 +02004394static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4395 u16 handle)
4396{
4397 struct mgmt_ev_adv_monitor_added ev;
4398
4399 ev.monitor_handle = cpu_to_le16(handle);
4400
4401 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4402}
4403
Archie Pusaka66bd0952021-01-22 16:36:13 +08004404void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004405{
Archie Pusaka66bd0952021-01-22 16:36:13 +08004406 struct mgmt_ev_adv_monitor_removed ev;
4407 struct mgmt_pending_cmd *cmd;
4408 struct sock *sk_skip = NULL;
4409 struct mgmt_cp_remove_adv_monitor *cp;
4410
4411 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4412 if (cmd) {
4413 cp = cmd->param;
4414
4415 if (cp->monitor_handle)
4416 sk_skip = cmd->sk;
4417 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004418
4419 ev.monitor_handle = cpu_to_le16(handle);
4420
Archie Pusaka66bd0952021-01-22 16:36:13 +08004421 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004422}
4423
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004424static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4425 void *data, u16 len)
4426{
4427 struct adv_monitor *monitor = NULL;
4428 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004429 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004430 size_t rp_size = 0;
4431 __u32 supported = 0;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004432 __u32 enabled = 0;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004433 __u16 num_handles = 0;
4434 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4435
4436 BT_DBG("request for %s", hdev->name);
4437
4438 hci_dev_lock(hdev);
4439
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004440 if (msft_monitor_supported(hdev))
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004441 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4442
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004443 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004444 handles[num_handles++] = monitor->handle;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004445
4446 hci_dev_unlock(hdev);
4447
4448 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4449 rp = kmalloc(rp_size, GFP_KERNEL);
4450 if (!rp)
4451 return -ENOMEM;
4452
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004453 /* All supported features are currently enabled */
4454 enabled = supported;
4455
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004456 rp->supported_features = cpu_to_le32(supported);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004457 rp->enabled_features = cpu_to_le32(enabled);
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004458 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4459 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4460 rp->num_handles = cpu_to_le16(num_handles);
4461 if (num_handles)
4462 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4463
Peilin Yecafd4722020-09-09 03:25:51 -04004464 err = mgmt_cmd_complete(sk, hdev->id,
4465 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4466 MGMT_STATUS_SUCCESS, rp, rp_size);
4467
4468 kfree(rp);
4469
4470 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004471}
4472
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004473int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
Miao-chen Choub1395532020-06-17 16:39:14 +02004474{
Miao-chen Choub1395532020-06-17 16:39:14 +02004475 struct mgmt_rp_add_adv_patterns_monitor rp;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004476 struct mgmt_pending_cmd *cmd;
4477 struct adv_monitor *monitor;
4478 int err = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004479
4480 hci_dev_lock(hdev);
4481
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004482 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4483 if (!cmd) {
4484 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4485 if (!cmd)
4486 goto done;
4487 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004488
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004489 monitor = cmd->user_data;
4490 rp.monitor_handle = cpu_to_le16(monitor->handle);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004491
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004492 if (!status) {
4493 mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4494 hdev->adv_monitors_cnt++;
4495 if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4496 monitor->state = ADV_MONITOR_STATE_REGISTERED;
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004497 hci_update_passive_scan(hdev);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004498 }
4499
4500 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4501 mgmt_status(status), &rp, sizeof(rp));
4502 mgmt_pending_remove(cmd);
4503
4504done:
4505 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004506 bt_dev_dbg(hdev, "add monitor %d complete, status %u",
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004507 rp.monitor_handle, status);
4508
4509 return err;
4510}
4511
4512static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4513 struct adv_monitor *m, u8 status,
4514 void *data, u16 len, u16 op)
4515{
4516 struct mgmt_rp_add_adv_patterns_monitor rp;
4517 struct mgmt_pending_cmd *cmd;
4518 int err;
4519 bool pending;
4520
4521 hci_dev_lock(hdev);
4522
4523 if (status)
4524 goto unlock;
4525
4526 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4527 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4528 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4529 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4530 status = MGMT_STATUS_BUSY;
Miao-chen Choub1395532020-06-17 16:39:14 +02004531 goto unlock;
4532 }
4533
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004534 cmd = mgmt_pending_add(sk, op, hdev, data, len);
4535 if (!cmd) {
4536 status = MGMT_STATUS_NO_RESOURCES;
4537 goto unlock;
4538 }
4539
Howard Chungb1810fe2021-02-03 15:09:29 +08004540 cmd->user_data = m;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004541 pending = hci_add_adv_monitor(hdev, m, &err);
4542 if (err) {
4543 if (err == -ENOSPC || err == -ENOMEM)
4544 status = MGMT_STATUS_NO_RESOURCES;
4545 else if (err == -EINVAL)
4546 status = MGMT_STATUS_INVALID_PARAMS;
4547 else
4548 status = MGMT_STATUS_FAILED;
4549
4550 mgmt_pending_remove(cmd);
4551 goto unlock;
4552 }
4553
4554 if (!pending) {
4555 mgmt_pending_remove(cmd);
4556 rp.monitor_handle = cpu_to_le16(m->handle);
Miao-chen Choub52729f2020-06-17 16:39:16 +02004557 mgmt_adv_monitor_added(sk, hdev, m->handle);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004558 m->state = ADV_MONITOR_STATE_REGISTERED;
4559 hdev->adv_monitors_cnt++;
4560
4561 hci_dev_unlock(hdev);
4562 return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4563 &rp, sizeof(rp));
4564 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004565
Miao-chen Choub1395532020-06-17 16:39:14 +02004566 hci_dev_unlock(hdev);
4567
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004568 return 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004569
4570unlock:
Archie Pusaka66bd0952021-01-22 16:36:13 +08004571 hci_free_adv_monitor(hdev, m);
Miao-chen Choub1395532020-06-17 16:39:14 +02004572 hci_dev_unlock(hdev);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004573 return mgmt_cmd_status(sk, hdev->id, op, status);
4574}
4575
4576static void parse_adv_monitor_rssi(struct adv_monitor *m,
4577 struct mgmt_adv_rssi_thresholds *rssi)
4578{
4579 if (rssi) {
4580 m->rssi.low_threshold = rssi->low_threshold;
4581 m->rssi.low_threshold_timeout =
4582 __le16_to_cpu(rssi->low_threshold_timeout);
4583 m->rssi.high_threshold = rssi->high_threshold;
4584 m->rssi.high_threshold_timeout =
4585 __le16_to_cpu(rssi->high_threshold_timeout);
4586 m->rssi.sampling_period = rssi->sampling_period;
4587 } else {
4588 /* Default values. These numbers are the least constricting
4589 * parameters for MSFT API to work, so it behaves as if there
4590 * are no rssi parameter to consider. May need to be changed
4591 * if other API are to be supported.
4592 */
4593 m->rssi.low_threshold = -127;
4594 m->rssi.low_threshold_timeout = 60;
4595 m->rssi.high_threshold = -127;
4596 m->rssi.high_threshold_timeout = 0;
4597 m->rssi.sampling_period = 0;
4598 }
4599}
4600
4601static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
4602 struct mgmt_adv_pattern *patterns)
4603{
4604 u8 offset = 0, length = 0;
4605 struct adv_pattern *p = NULL;
Archie Pusakab4a221e2021-01-22 16:36:11 +08004606 int i;
4607
4608 for (i = 0; i < pattern_count; i++) {
Archie Pusakab4a221e2021-01-22 16:36:11 +08004609 offset = patterns[i].offset;
4610 length = patterns[i].length;
4611 if (offset >= HCI_MAX_AD_LENGTH ||
4612 length > HCI_MAX_AD_LENGTH ||
4613 (offset + length) > HCI_MAX_AD_LENGTH)
4614 return MGMT_STATUS_INVALID_PARAMS;
4615
4616 p = kmalloc(sizeof(*p), GFP_KERNEL);
4617 if (!p)
4618 return MGMT_STATUS_NO_RESOURCES;
4619
4620 p->ad_type = patterns[i].ad_type;
4621 p->offset = patterns[i].offset;
4622 p->length = patterns[i].length;
4623 memcpy(p->value, patterns[i].value, p->length);
4624
4625 INIT_LIST_HEAD(&p->list);
4626 list_add(&p->list, &m->patterns);
4627 }
4628
Archie Pusakab4a221e2021-01-22 16:36:11 +08004629 return MGMT_STATUS_SUCCESS;
4630}
4631
4632static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4633 void *data, u16 len)
4634{
4635 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4636 struct adv_monitor *m = NULL;
4637 u8 status = MGMT_STATUS_SUCCESS;
4638 size_t expected_size = sizeof(*cp);
4639
4640 BT_DBG("request for %s", hdev->name);
4641
4642 if (len <= sizeof(*cp)) {
4643 status = MGMT_STATUS_INVALID_PARAMS;
4644 goto done;
4645 }
4646
4647 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4648 if (len != expected_size) {
4649 status = MGMT_STATUS_INVALID_PARAMS;
4650 goto done;
4651 }
4652
4653 m = kzalloc(sizeof(*m), GFP_KERNEL);
4654 if (!m) {
4655 status = MGMT_STATUS_NO_RESOURCES;
4656 goto done;
4657 }
4658
4659 INIT_LIST_HEAD(&m->patterns);
4660
4661 parse_adv_monitor_rssi(m, NULL);
4662 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4663
4664done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004665 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004666 MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
4667}
4668
4669static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
4670 void *data, u16 len)
4671{
4672 struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = data;
4673 struct adv_monitor *m = NULL;
4674 u8 status = MGMT_STATUS_SUCCESS;
4675 size_t expected_size = sizeof(*cp);
4676
4677 BT_DBG("request for %s", hdev->name);
4678
4679 if (len <= sizeof(*cp)) {
4680 status = MGMT_STATUS_INVALID_PARAMS;
4681 goto done;
4682 }
4683
4684 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4685 if (len != expected_size) {
4686 status = MGMT_STATUS_INVALID_PARAMS;
4687 goto done;
4688 }
4689
4690 m = kzalloc(sizeof(*m), GFP_KERNEL);
4691 if (!m) {
4692 status = MGMT_STATUS_NO_RESOURCES;
4693 goto done;
4694 }
4695
4696 INIT_LIST_HEAD(&m->patterns);
4697
4698 parse_adv_monitor_rssi(m, &cp->rssi);
4699 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4700
4701done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004702 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004703 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
Miao-chen Choub1395532020-06-17 16:39:14 +02004704}
4705
Archie Pusaka66bd0952021-01-22 16:36:13 +08004706int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4707{
4708 struct mgmt_rp_remove_adv_monitor rp;
4709 struct mgmt_cp_remove_adv_monitor *cp;
4710 struct mgmt_pending_cmd *cmd;
4711 int err = 0;
4712
4713 hci_dev_lock(hdev);
4714
4715 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4716 if (!cmd)
4717 goto done;
4718
4719 cp = cmd->param;
4720 rp.monitor_handle = cp->monitor_handle;
4721
4722 if (!status)
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004723 hci_update_passive_scan(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004724
4725 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4726 mgmt_status(status), &rp, sizeof(rp));
4727 mgmt_pending_remove(cmd);
4728
4729done:
4730 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004731 bt_dev_dbg(hdev, "remove monitor %d complete, status %u",
Archie Pusaka66bd0952021-01-22 16:36:13 +08004732 rp.monitor_handle, status);
4733
4734 return err;
4735}
4736
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004737static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4738 void *data, u16 len)
4739{
4740 struct mgmt_cp_remove_adv_monitor *cp = data;
4741 struct mgmt_rp_remove_adv_monitor rp;
Archie Pusaka66bd0952021-01-22 16:36:13 +08004742 struct mgmt_pending_cmd *cmd;
4743 u16 handle = __le16_to_cpu(cp->monitor_handle);
4744 int err, status;
4745 bool pending;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004746
4747 BT_DBG("request for %s", hdev->name);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004748 rp.monitor_handle = cp->monitor_handle;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004749
4750 hci_dev_lock(hdev);
4751
Archie Pusaka66bd0952021-01-22 16:36:13 +08004752 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4753 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4754 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4755 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4756 status = MGMT_STATUS_BUSY;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004757 goto unlock;
4758 }
4759
Archie Pusaka66bd0952021-01-22 16:36:13 +08004760 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4761 if (!cmd) {
4762 status = MGMT_STATUS_NO_RESOURCES;
4763 goto unlock;
4764 }
4765
4766 if (handle)
4767 pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4768 else
4769 pending = hci_remove_all_adv_monitor(hdev, &err);
4770
4771 if (err) {
4772 mgmt_pending_remove(cmd);
4773
4774 if (err == -ENOENT)
4775 status = MGMT_STATUS_INVALID_INDEX;
4776 else
4777 status = MGMT_STATUS_FAILED;
4778
4779 goto unlock;
4780 }
4781
4782 /* monitor can be removed without forwarding request to controller */
4783 if (!pending) {
4784 mgmt_pending_remove(cmd);
4785 hci_dev_unlock(hdev);
4786
4787 return mgmt_cmd_complete(sk, hdev->id,
4788 MGMT_OP_REMOVE_ADV_MONITOR,
4789 MGMT_STATUS_SUCCESS,
4790 &rp, sizeof(rp));
4791 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004792
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004793 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004794 return 0;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004795
4796unlock:
4797 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4799 status);
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004800}
4801
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004802static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4803 u16 opcode, struct sk_buff *skb)
4804{
4805 struct mgmt_rp_read_local_oob_data mgmt_rp;
4806 size_t rp_size = sizeof(mgmt_rp);
4807 struct mgmt_pending_cmd *cmd;
4808
Marcel Holtmann181d6952020-05-06 09:57:47 +02004809 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004810
4811 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4812 if (!cmd)
4813 return;
4814
4815 if (status || !skb) {
4816 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4817 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4818 goto remove;
4819 }
4820
4821 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4822
4823 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4824 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4825
4826 if (skb->len < sizeof(*rp)) {
4827 mgmt_cmd_status(cmd->sk, hdev->id,
4828 MGMT_OP_READ_LOCAL_OOB_DATA,
4829 MGMT_STATUS_FAILED);
4830 goto remove;
4831 }
4832
4833 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4834 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4835
4836 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4837 } else {
4838 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4839
4840 if (skb->len < sizeof(*rp)) {
4841 mgmt_cmd_status(cmd->sk, hdev->id,
4842 MGMT_OP_READ_LOCAL_OOB_DATA,
4843 MGMT_STATUS_FAILED);
4844 goto remove;
4845 }
4846
4847 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4848 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4849
4850 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4851 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4852 }
4853
4854 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4855 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4856
4857remove:
4858 mgmt_pending_remove(cmd);
4859}
4860
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004861static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004862 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004863{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004864 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004865 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004866 int err;
4867
Marcel Holtmann181d6952020-05-06 09:57:47 +02004868 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004870 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004871
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004872 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004873 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4874 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004875 goto unlock;
4876 }
4877
Andre Guedes9a1a1992012-07-24 15:03:48 -03004878 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004879 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4880 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004881 goto unlock;
4882 }
4883
Johan Hedberg333ae952015-03-17 13:48:47 +02004884 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004885 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4886 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004887 goto unlock;
4888 }
4889
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004890 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004891 if (!cmd) {
4892 err = -ENOMEM;
4893 goto unlock;
4894 }
4895
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004896 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004897
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004898 if (bredr_sc_enabled(hdev))
4899 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4900 else
4901 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4902
4903 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004904 if (err < 0)
4905 mgmt_pending_remove(cmd);
4906
4907unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004908 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004909 return err;
4910}
4911
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004912static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004913 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004914{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004915 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004916 int err;
4917
Marcel Holtmann181d6952020-05-06 09:57:47 +02004918 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004919
Johan Hedberg5d57e792015-01-23 10:10:38 +02004920 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004921 return mgmt_cmd_complete(sk, hdev->id,
4922 MGMT_OP_ADD_REMOTE_OOB_DATA,
4923 MGMT_STATUS_INVALID_PARAMS,
4924 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004925
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004926 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004927
Marcel Holtmannec109112014-01-10 02:07:30 -08004928 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4929 struct mgmt_cp_add_remote_oob_data *cp = data;
4930 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004931
Johan Hedbergc19a4952014-11-17 20:52:19 +02004932 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004933 err = mgmt_cmd_complete(sk, hdev->id,
4934 MGMT_OP_ADD_REMOTE_OOB_DATA,
4935 MGMT_STATUS_INVALID_PARAMS,
4936 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004937 goto unlock;
4938 }
4939
Marcel Holtmannec109112014-01-10 02:07:30 -08004940 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004941 cp->addr.type, cp->hash,
4942 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004943 if (err < 0)
4944 status = MGMT_STATUS_FAILED;
4945 else
4946 status = MGMT_STATUS_SUCCESS;
4947
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004948 err = mgmt_cmd_complete(sk, hdev->id,
4949 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4950 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004951 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4952 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004953 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004954 u8 status;
4955
Johan Hedberg86df9202014-10-26 20:52:27 +01004956 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004957 /* Enforce zero-valued 192-bit parameters as
4958 * long as legacy SMP OOB isn't implemented.
4959 */
4960 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4961 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004962 err = mgmt_cmd_complete(sk, hdev->id,
4963 MGMT_OP_ADD_REMOTE_OOB_DATA,
4964 MGMT_STATUS_INVALID_PARAMS,
4965 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004966 goto unlock;
4967 }
4968
Johan Hedberg86df9202014-10-26 20:52:27 +01004969 rand192 = NULL;
4970 hash192 = NULL;
4971 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004972 /* In case one of the P-192 values is set to zero,
4973 * then just disable OOB data for P-192.
4974 */
4975 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4976 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4977 rand192 = NULL;
4978 hash192 = NULL;
4979 } else {
4980 rand192 = cp->rand192;
4981 hash192 = cp->hash192;
4982 }
4983 }
4984
4985 /* In case one of the P-256 values is set to zero, then just
4986 * disable OOB data for P-256.
4987 */
4988 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4989 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4990 rand256 = NULL;
4991 hash256 = NULL;
4992 } else {
4993 rand256 = cp->rand256;
4994 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004995 }
4996
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004997 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004998 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004999 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08005000 if (err < 0)
5001 status = MGMT_STATUS_FAILED;
5002 else
5003 status = MGMT_STATUS_SUCCESS;
5004
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005005 err = mgmt_cmd_complete(sk, hdev->id,
5006 MGMT_OP_ADD_REMOTE_OOB_DATA,
5007 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08005008 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005009 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
5010 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005011 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
5012 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08005013 }
Szymon Janc2763eda2011-03-22 13:12:22 +01005014
Johan Hedbergc19a4952014-11-17 20:52:19 +02005015unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005016 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005017 return err;
5018}
5019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005020static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005021 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01005022{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005023 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005024 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01005025 int err;
5026
Marcel Holtmann181d6952020-05-06 09:57:47 +02005027 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01005028
Johan Hedbergc19a4952014-11-17 20:52:19 +02005029 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005030 return mgmt_cmd_complete(sk, hdev->id,
5031 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5032 MGMT_STATUS_INVALID_PARAMS,
5033 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02005034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005035 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005036
Johan Hedbergeedbd582014-11-15 09:34:23 +02005037 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5038 hci_remote_oob_data_clear(hdev);
5039 status = MGMT_STATUS_SUCCESS;
5040 goto done;
5041 }
5042
Johan Hedberg6928a922014-10-26 20:46:09 +01005043 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01005044 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005045 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01005046 else
Szymon Janca6785be2012-12-13 15:11:21 +01005047 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005048
Johan Hedbergeedbd582014-11-15 09:34:23 +02005049done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005050 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5051 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01005052
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005053 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005054 return err;
5055}
5056
Johan Hedberge68f0722015-11-11 08:30:30 +02005057void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03005058{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005059 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01005060
Kai Ye85d672842021-06-03 15:41:02 +08005061 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes7c307722013-04-30 15:29:28 -03005062
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005063 hci_dev_lock(hdev);
5064
Johan Hedberg333ae952015-03-17 13:48:47 +02005065 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005066 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02005067 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005068
Johan Hedberg78b781c2016-01-05 13:19:32 +02005069 if (!cmd)
5070 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
5071
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005072 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005073 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005074 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03005075 }
5076
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005077 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005078
5079 /* Handle suspend notifier */
5080 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
5081 hdev->suspend_tasks)) {
5082 bt_dev_dbg(hdev, "Unpaused discovery");
5083 wake_up(&hdev->suspend_wait_q);
5084 }
Andre Guedes7c307722013-04-30 15:29:28 -03005085}
5086
Johan Hedberg591752a2015-11-11 08:11:24 +02005087static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
5088 uint8_t *mgmt_status)
5089{
5090 switch (type) {
5091 case DISCOV_TYPE_LE:
5092 *mgmt_status = mgmt_le_support(hdev);
5093 if (*mgmt_status)
5094 return false;
5095 break;
5096 case DISCOV_TYPE_INTERLEAVED:
5097 *mgmt_status = mgmt_le_support(hdev);
5098 if (*mgmt_status)
5099 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05005100 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02005101 case DISCOV_TYPE_BREDR:
5102 *mgmt_status = mgmt_bredr_support(hdev);
5103 if (*mgmt_status)
5104 return false;
5105 break;
5106 default:
5107 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
5108 return false;
5109 }
5110
5111 return true;
5112}
5113
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005114static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
5115{
5116 struct mgmt_pending_cmd *cmd = data;
5117
5118 bt_dev_dbg(hdev, "err %d", err);
5119
5120 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5121 cmd->param, 1);
5122 mgmt_pending_free(cmd);
5123
5124 /* Handle suspend notifier */
5125 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
5126 hdev->suspend_tasks)) {
5127 bt_dev_dbg(hdev, "Unpaused discovery");
5128 wake_up(&hdev->suspend_wait_q);
5129 }
5130
5131 hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED :
5132 DISCOVERY_FINDING);
5133}
5134
5135static int start_discovery_sync(struct hci_dev *hdev, void *data)
5136{
5137 return hci_start_discovery_sync(hdev);
5138}
5139
Johan Hedberg78b781c2016-01-05 13:19:32 +02005140static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
5141 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005142{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005143 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005144 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01005145 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04005146 int err;
5147
Marcel Holtmann181d6952020-05-06 09:57:47 +02005148 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005150 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005151
Johan Hedberg4b34ee782012-02-21 14:13:02 +02005152 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005153 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005154 MGMT_STATUS_NOT_POWERED,
5155 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02005156 goto failed;
5157 }
5158
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005159 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005160 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005161 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5162 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03005163 goto failed;
5164 }
5165
Johan Hedberg591752a2015-11-11 08:11:24 +02005166 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005167 err = mgmt_cmd_complete(sk, hdev->id, op, status,
5168 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02005169 goto failed;
5170 }
5171
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005172 /* Can't start discovery when it is paused */
5173 if (hdev->discovery_paused) {
5174 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5175 &cp->type, sizeof(cp->type));
5176 goto failed;
5177 }
5178
Marcel Holtmann22078802014-12-05 11:45:22 +01005179 /* Clear the discovery filter first to free any previously
5180 * allocated memory for the UUID list.
5181 */
5182 hci_discovery_filter_clear(hdev);
5183
Andre Guedes4aab14e2012-02-17 20:39:36 -03005184 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01005185 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02005186 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
5187 hdev->discovery.limited = true;
5188 else
5189 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03005190
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005191 cmd = mgmt_pending_new(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02005192 if (!cmd) {
5193 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02005194 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03005195 }
Andre Guedes3fd24152012-02-03 17:48:01 -03005196
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005197 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5198 start_discovery_complete);
5199 if (err < 0) {
5200 mgmt_pending_free(cmd);
5201 goto failed;
5202 }
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005203
5204 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005205
5206failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005207 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005208 return err;
5209}
5210
Johan Hedberg78b781c2016-01-05 13:19:32 +02005211static int start_discovery(struct sock *sk, struct hci_dev *hdev,
5212 void *data, u16 len)
5213{
5214 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
5215 data, len);
5216}
5217
5218static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
5219 void *data, u16 len)
5220{
5221 return start_discovery_internal(sk, hdev,
5222 MGMT_OP_START_LIMITED_DISCOVERY,
5223 data, len);
5224}
5225
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005226static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
5227 void *data, u16 len)
5228{
5229 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005230 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005231 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
5232 u16 uuid_count, expected_len;
5233 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03005234 int err;
5235
Marcel Holtmann181d6952020-05-06 09:57:47 +02005236 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005237
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005238 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005239
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005241 err = mgmt_cmd_complete(sk, hdev->id,
5242 MGMT_OP_START_SERVICE_DISCOVERY,
5243 MGMT_STATUS_NOT_POWERED,
5244 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005245 goto failed;
5246 }
5247
5248 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005249 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005250 err = mgmt_cmd_complete(sk, hdev->id,
5251 MGMT_OP_START_SERVICE_DISCOVERY,
5252 MGMT_STATUS_BUSY, &cp->type,
5253 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005254 goto failed;
5255 }
5256
Abhishek Pandit-Subedi36211f72020-12-17 15:04:08 -08005257 if (hdev->discovery_paused) {
5258 err = mgmt_cmd_complete(sk, hdev->id,
5259 MGMT_OP_START_SERVICE_DISCOVERY,
5260 MGMT_STATUS_BUSY, &cp->type,
5261 sizeof(cp->type));
5262 goto failed;
5263 }
5264
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005265 uuid_count = __le16_to_cpu(cp->uuid_count);
5266 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005267 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
5268 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005269 err = mgmt_cmd_complete(sk, hdev->id,
5270 MGMT_OP_START_SERVICE_DISCOVERY,
5271 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5272 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005273 goto failed;
5274 }
5275
5276 expected_len = sizeof(*cp) + uuid_count * 16;
5277 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005278 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
5279 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005280 err = mgmt_cmd_complete(sk, hdev->id,
5281 MGMT_OP_START_SERVICE_DISCOVERY,
5282 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5283 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005284 goto failed;
5285 }
5286
Johan Hedberg591752a2015-11-11 08:11:24 +02005287 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
5288 err = mgmt_cmd_complete(sk, hdev->id,
5289 MGMT_OP_START_SERVICE_DISCOVERY,
5290 status, &cp->type, sizeof(cp->type));
5291 goto failed;
5292 }
5293
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005294 cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02005295 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005296 if (!cmd) {
5297 err = -ENOMEM;
5298 goto failed;
5299 }
5300
Marcel Holtmann22078802014-12-05 11:45:22 +01005301 /* Clear the discovery filter first to free any previously
5302 * allocated memory for the UUID list.
5303 */
5304 hci_discovery_filter_clear(hdev);
5305
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08005306 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005307 hdev->discovery.type = cp->type;
5308 hdev->discovery.rssi = cp->rssi;
5309 hdev->discovery.uuid_count = uuid_count;
5310
5311 if (uuid_count > 0) {
5312 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
5313 GFP_KERNEL);
5314 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005315 err = mgmt_cmd_complete(sk, hdev->id,
5316 MGMT_OP_START_SERVICE_DISCOVERY,
5317 MGMT_STATUS_FAILED,
5318 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005319 mgmt_pending_remove(cmd);
5320 goto failed;
5321 }
5322 }
5323
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005324 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5325 start_discovery_complete);
5326 if (err < 0) {
5327 mgmt_pending_free(cmd);
5328 goto failed;
5329 }
5330
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005331 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
5332
5333failed:
5334 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005335 return err;
5336}
5337
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005338void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03005339{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005340 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005341
Kai Ye85d672842021-06-03 15:41:02 +08005342 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005343
5344 hci_dev_lock(hdev);
5345
Johan Hedberg333ae952015-03-17 13:48:47 +02005346 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005347 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005348 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005349 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005350 }
5351
Andre Guedes0e05bba2013-04-30 15:29:33 -03005352 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005353
5354 /* Handle suspend notifier */
5355 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
5356 bt_dev_dbg(hdev, "Paused discovery");
5357 wake_up(&hdev->suspend_wait_q);
5358 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03005359}
5360
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005361static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
5362{
5363 struct mgmt_pending_cmd *cmd = data;
5364
5365 bt_dev_dbg(hdev, "err %d", err);
5366
5367 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5368 cmd->param, 1);
5369 mgmt_pending_free(cmd);
5370
5371 /* Handle suspend notifier */
5372 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
5373 bt_dev_dbg(hdev, "Paused discovery");
5374 wake_up(&hdev->suspend_wait_q);
5375 }
5376
5377 if (!err)
5378 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
5379}
5380
5381static int stop_discovery_sync(struct hci_dev *hdev, void *data)
5382{
5383 return hci_stop_discovery_sync(hdev);
5384}
5385
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005386static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005387 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005388{
Johan Hedbergd9306502012-02-20 23:25:18 +02005389 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005390 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04005391 int err;
5392
Marcel Holtmann181d6952020-05-06 09:57:47 +02005393 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005395 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005396
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005397 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005398 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5399 MGMT_STATUS_REJECTED, &mgmt_cp->type,
5400 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02005401 goto unlock;
5402 }
5403
5404 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005405 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5406 MGMT_STATUS_INVALID_PARAMS,
5407 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005408 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02005409 }
5410
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005411 cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04005412 if (!cmd) {
5413 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005414 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04005415 }
5416
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005417 err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd,
5418 stop_discovery_complete);
5419 if (err < 0) {
5420 mgmt_pending_free(cmd);
5421 goto unlock;
5422 }
Johan Hedberg2922a942014-12-05 13:36:06 +02005423
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005424 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005425
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005426unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005427 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005428 return err;
5429}
5430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005431static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005432 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02005433{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005434 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005435 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005436 int err;
5437
Marcel Holtmann181d6952020-05-06 09:57:47 +02005438 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005439
Johan Hedberg561aafb2012-01-04 13:31:59 +02005440 hci_dev_lock(hdev);
5441
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005442 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005443 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5444 MGMT_STATUS_FAILED, &cp->addr,
5445 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005446 goto failed;
5447 }
5448
Johan Hedberga198e7b2012-02-17 14:27:06 +02005449 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005450 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005451 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5452 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
5453 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005454 goto failed;
5455 }
5456
5457 if (cp->name_known) {
5458 e->name_state = NAME_KNOWN;
5459 list_del(&e->list);
5460 } else {
5461 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02005462 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005463 }
5464
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005465 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
5466 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005467
5468failed:
5469 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005470 return err;
5471}
5472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005473static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005474 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005475{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005476 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005477 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005478 int err;
5479
Marcel Holtmann181d6952020-05-06 09:57:47 +02005480 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005481
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005482 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005483 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
5484 MGMT_STATUS_INVALID_PARAMS,
5485 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005487 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005488
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005489 err = hci_bdaddr_list_add(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005490 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005491 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005492 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005493 goto done;
5494 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005495
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005496 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5497 sk);
5498 status = MGMT_STATUS_SUCCESS;
5499
5500done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005501 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
5502 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005504 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005505
5506 return err;
5507}
5508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005509static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005510 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005511{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005512 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005513 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005514 int err;
5515
Marcel Holtmann181d6952020-05-06 09:57:47 +02005516 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005517
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005518 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005519 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5520 MGMT_STATUS_INVALID_PARAMS,
5521 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005523 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005524
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005525 err = hci_bdaddr_list_del(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005526 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005527 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005528 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005529 goto done;
5530 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005531
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005532 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5533 sk);
5534 status = MGMT_STATUS_SUCCESS;
5535
5536done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005537 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5538 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005540 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005541
5542 return err;
5543}
5544
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005545static int set_device_id_sync(struct hci_dev *hdev, void *data)
5546{
5547 return hci_update_eir_sync(hdev);
5548}
5549
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005550static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5551 u16 len)
5552{
5553 struct mgmt_cp_set_device_id *cp = data;
5554 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005555 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005556
Marcel Holtmann181d6952020-05-06 09:57:47 +02005557 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005558
Szymon Jancc72d4b82012-03-16 16:02:57 +01005559 source = __le16_to_cpu(cp->source);
5560
5561 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005562 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5563 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005564
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005565 hci_dev_lock(hdev);
5566
Szymon Jancc72d4b82012-03-16 16:02:57 +01005567 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005568 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5569 hdev->devid_product = __le16_to_cpu(cp->product);
5570 hdev->devid_version = __le16_to_cpu(cp->version);
5571
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005572 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5573 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005574
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005575 hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005576
5577 hci_dev_unlock(hdev);
5578
5579 return err;
5580}
5581
Arman Uguray24b4f382015-03-23 15:57:12 -07005582static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5583 u16 opcode)
5584{
Kai Ye85d672842021-06-03 15:41:02 +08005585 bt_dev_dbg(hdev, "status %u", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005586}
5587
Marcel Holtmann1904a852015-01-11 13:50:44 -08005588static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5589 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005590{
5591 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005592 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005593 u8 instance;
5594 struct adv_info *adv_instance;
5595 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005596
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305597 hci_dev_lock(hdev);
5598
Johan Hedberg4375f102013-09-25 13:26:10 +03005599 if (status) {
5600 u8 mgmt_err = mgmt_status(status);
5601
5602 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5603 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305604 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005605 }
5606
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005607 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005608 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005609 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005610 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005611
Johan Hedberg4375f102013-09-25 13:26:10 +03005612 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5613 &match);
5614
5615 new_settings(hdev, match.sk);
5616
5617 if (match.sk)
5618 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305619
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005620 /* Handle suspend notifier */
5621 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5622 hdev->suspend_tasks)) {
5623 bt_dev_dbg(hdev, "Paused advertising");
5624 wake_up(&hdev->suspend_wait_q);
5625 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5626 hdev->suspend_tasks)) {
5627 bt_dev_dbg(hdev, "Unpaused advertising");
5628 wake_up(&hdev->suspend_wait_q);
5629 }
5630
Arman Uguray24b4f382015-03-23 15:57:12 -07005631 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005632 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005633 */
5634 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005635 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005636 goto unlock;
5637
Florian Grandel7816b822015-06-18 03:16:45 +02005638 instance = hdev->cur_adv_instance;
5639 if (!instance) {
5640 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5641 struct adv_info, list);
5642 if (!adv_instance)
5643 goto unlock;
5644
5645 instance = adv_instance->instance;
5646 }
5647
Arman Uguray24b4f382015-03-23 15:57:12 -07005648 hci_req_init(&req, hdev);
5649
Johan Hedbergf2252572015-11-18 12:49:20 +02005650 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005651
Florian Grandel7816b822015-06-18 03:16:45 +02005652 if (!err)
5653 err = hci_req_run(&req, enable_advertising_instance);
5654
5655 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005656 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005657
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305658unlock:
5659 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005660}
5661
Marcel Holtmann21b51872013-10-10 09:47:53 -07005662static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5663 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005664{
5665 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005666 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005667 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005668 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005669 int err;
5670
Marcel Holtmann181d6952020-05-06 09:57:47 +02005671 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005672
Johan Hedberge6fe7982013-10-02 15:45:22 +03005673 status = mgmt_le_support(hdev);
5674 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005675 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5676 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005677
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005678 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005679 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5680 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005681
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005682 if (hdev->advertising_paused)
5683 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5684 MGMT_STATUS_BUSY);
5685
Johan Hedberg4375f102013-09-25 13:26:10 +03005686 hci_dev_lock(hdev);
5687
5688 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005689
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005690 /* The following conditions are ones which mean that we should
5691 * not do any HCI communication but directly send a mgmt
5692 * response to user space (after toggling the flag if
5693 * necessary).
5694 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005695 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005696 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5697 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005698 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005699 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005700 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005701 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005702
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005703 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005704 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005705 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005706 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005707 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005708 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005709 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005710 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005711 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005712 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005713 }
5714
5715 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5716 if (err < 0)
5717 goto unlock;
5718
5719 if (changed)
5720 err = new_settings(hdev, sk);
5721
5722 goto unlock;
5723 }
5724
Johan Hedberg333ae952015-03-17 13:48:47 +02005725 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5726 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5728 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005729 goto unlock;
5730 }
5731
5732 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5733 if (!cmd) {
5734 err = -ENOMEM;
5735 goto unlock;
5736 }
5737
5738 hci_req_init(&req, hdev);
5739
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005740 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005741 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005742 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005743 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005744
Florian Grandel7816b822015-06-18 03:16:45 +02005745 cancel_adv_timeout(hdev);
5746
Arman Uguray24b4f382015-03-23 15:57:12 -07005747 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005748 /* Switch to instance "0" for the Set Advertising setting.
5749 * We cannot use update_[adv|scan_rsp]_data() here as the
5750 * HCI_ADVERTISING flag is not yet set.
5751 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005752 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305753
5754 if (ext_adv_capable(hdev)) {
5755 __hci_req_start_ext_adv(&req, 0x00);
5756 } else {
5757 __hci_req_update_adv_data(&req, 0x00);
5758 __hci_req_update_scan_rsp_data(&req, 0x00);
5759 __hci_req_enable_advertising(&req);
5760 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005761 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005762 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005763 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005764
5765 err = hci_req_run(&req, set_advertising_complete);
5766 if (err < 0)
5767 mgmt_pending_remove(cmd);
5768
5769unlock:
5770 hci_dev_unlock(hdev);
5771 return err;
5772}
5773
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005774static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5775 void *data, u16 len)
5776{
5777 struct mgmt_cp_set_static_address *cp = data;
5778 int err;
5779
Marcel Holtmann181d6952020-05-06 09:57:47 +02005780 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005781
Marcel Holtmann62af4442013-10-02 22:10:32 -07005782 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005783 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5784 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005785
5786 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005787 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5788 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005789
5790 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5791 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005792 return mgmt_cmd_status(sk, hdev->id,
5793 MGMT_OP_SET_STATIC_ADDRESS,
5794 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005795
5796 /* Two most significant bits shall be set */
5797 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005798 return mgmt_cmd_status(sk, hdev->id,
5799 MGMT_OP_SET_STATIC_ADDRESS,
5800 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005801 }
5802
5803 hci_dev_lock(hdev);
5804
5805 bacpy(&hdev->static_addr, &cp->bdaddr);
5806
Marcel Holtmann93690c22015-03-06 10:11:21 -08005807 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5808 if (err < 0)
5809 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005810
Marcel Holtmann93690c22015-03-06 10:11:21 -08005811 err = new_settings(hdev, sk);
5812
5813unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005814 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005815 return err;
5816}
5817
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005818static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5819 void *data, u16 len)
5820{
5821 struct mgmt_cp_set_scan_params *cp = data;
5822 __u16 interval, window;
5823 int err;
5824
Marcel Holtmann181d6952020-05-06 09:57:47 +02005825 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005826
5827 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005828 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5829 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005830
5831 interval = __le16_to_cpu(cp->interval);
5832
5833 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005834 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5835 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005836
5837 window = __le16_to_cpu(cp->window);
5838
5839 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005840 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5841 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005842
Marcel Holtmann899e1072013-10-14 09:55:32 -07005843 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005844 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5845 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005846
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005847 hci_dev_lock(hdev);
5848
5849 hdev->le_scan_interval = interval;
5850 hdev->le_scan_window = window;
5851
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005852 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5853 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005854
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005855 /* If background scan is running, restart it so new parameters are
5856 * loaded.
5857 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005858 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005859 hdev->discovery.state == DISCOVERY_STOPPED)
5860 hci_update_passive_scan(hdev);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005861
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005862 hci_dev_unlock(hdev);
5863
5864 return err;
5865}
5866
Marcel Holtmann1904a852015-01-11 13:50:44 -08005867static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5868 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005870 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005871
Marcel Holtmann181d6952020-05-06 09:57:47 +02005872 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005873
5874 hci_dev_lock(hdev);
5875
Johan Hedberg333ae952015-03-17 13:48:47 +02005876 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005877 if (!cmd)
5878 goto unlock;
5879
5880 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005881 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5882 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005883 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005884 struct mgmt_mode *cp = cmd->param;
5885
5886 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005887 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005888 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005889 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005890
Johan Hedberg33e38b32013-03-15 17:07:05 -05005891 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5892 new_settings(hdev, cmd->sk);
5893 }
5894
5895 mgmt_pending_remove(cmd);
5896
5897unlock:
5898 hci_dev_unlock(hdev);
5899}
5900
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005901static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005902 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005903{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005904 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005905 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005906 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005907 int err;
5908
Marcel Holtmann181d6952020-05-06 09:57:47 +02005909 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005910
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005911 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005912 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005913 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5914 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005915
Johan Hedberga7e80f22013-01-09 16:05:19 +02005916 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005917 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5918 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005919
Antti Julkuf6422ec2011-06-22 13:11:56 +03005920 hci_dev_lock(hdev);
5921
Johan Hedberg333ae952015-03-17 13:48:47 +02005922 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005923 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5924 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005925 goto unlock;
5926 }
5927
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005928 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005929 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5930 hdev);
5931 goto unlock;
5932 }
5933
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005934 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005935 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005936 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5937 hdev);
5938 new_settings(hdev, sk);
5939 goto unlock;
5940 }
5941
Johan Hedberg33e38b32013-03-15 17:07:05 -05005942 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5943 data, len);
5944 if (!cmd) {
5945 err = -ENOMEM;
5946 goto unlock;
5947 }
5948
5949 hci_req_init(&req, hdev);
5950
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005951 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005952
5953 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005954 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005955 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5956 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005957 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005958 }
5959
Johan Hedberg33e38b32013-03-15 17:07:05 -05005960unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005961 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005962
Antti Julkuf6422ec2011-06-22 13:11:56 +03005963 return err;
5964}
5965
Marcel Holtmann1904a852015-01-11 13:50:44 -08005966static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005967{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005968 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005969
Marcel Holtmann181d6952020-05-06 09:57:47 +02005970 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005971
5972 hci_dev_lock(hdev);
5973
Johan Hedberg333ae952015-03-17 13:48:47 +02005974 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005975 if (!cmd)
5976 goto unlock;
5977
5978 if (status) {
5979 u8 mgmt_err = mgmt_status(status);
5980
5981 /* We need to restore the flag if related HCI commands
5982 * failed.
5983 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005984 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005985
Johan Hedberga69e8372015-03-06 21:08:53 +02005986 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005987 } else {
5988 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5989 new_settings(hdev, cmd->sk);
5990 }
5991
5992 mgmt_pending_remove(cmd);
5993
5994unlock:
5995 hci_dev_unlock(hdev);
5996}
5997
5998static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5999{
6000 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006001 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006002 struct hci_request req;
6003 int err;
6004
Marcel Holtmann181d6952020-05-06 09:57:47 +02006005 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006006
6007 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006008 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6009 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006010
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006011 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006012 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6013 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006014
6015 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006016 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6017 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006018
6019 hci_dev_lock(hdev);
6020
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006021 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03006022 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6023 goto unlock;
6024 }
6025
6026 if (!hdev_is_powered(hdev)) {
6027 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006028 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
6029 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
6030 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
6031 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
6032 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006033 }
6034
Marcel Holtmannce05d602015-03-13 02:11:03 -07006035 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006036
6037 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6038 if (err < 0)
6039 goto unlock;
6040
6041 err = new_settings(hdev, sk);
6042 goto unlock;
6043 }
6044
6045 /* Reject disabling when powered on */
6046 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006047 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6048 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006049 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006050 } else {
6051 /* When configuring a dual-mode controller to operate
6052 * with LE only and using a static address, then switching
6053 * BR/EDR back on is not allowed.
6054 *
6055 * Dual-mode controllers shall operate with the public
6056 * address as its identity address for BR/EDR and LE. So
6057 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006058 *
6059 * The same restrictions applies when secure connections
6060 * has been enabled. For BR/EDR this is a controller feature
6061 * while for LE it is a host stack feature. This means that
6062 * switching BR/EDR back on when secure connections has been
6063 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006064 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006065 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006066 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006067 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006068 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6069 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006070 goto unlock;
6071 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03006072 }
6073
Johan Hedberg333ae952015-03-17 13:48:47 +02006074 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006075 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6076 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006077 goto unlock;
6078 }
6079
6080 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
6081 if (!cmd) {
6082 err = -ENOMEM;
6083 goto unlock;
6084 }
6085
Johan Hedbergf2252572015-11-18 12:49:20 +02006086 /* We need to flip the bit already here so that
6087 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03006088 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006089 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006090
6091 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03006092
Johan Hedbergbf943cb2015-11-25 16:15:43 +02006093 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006094 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03006095
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006096 /* Since only the advertising data flags will change, there
6097 * is no need to update the scan response data.
6098 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02006099 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03006100
Johan Hedberg0663ca22013-10-02 13:43:14 +03006101 err = hci_req_run(&req, set_bredr_complete);
6102 if (err < 0)
6103 mgmt_pending_remove(cmd);
6104
6105unlock:
6106 hci_dev_unlock(hdev);
6107 return err;
6108}
6109
Johan Hedberga1443f52015-01-23 15:42:46 +02006110static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
6111{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006112 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02006113 struct mgmt_mode *cp;
6114
Marcel Holtmann181d6952020-05-06 09:57:47 +02006115 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02006116
6117 hci_dev_lock(hdev);
6118
Johan Hedberg333ae952015-03-17 13:48:47 +02006119 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02006120 if (!cmd)
6121 goto unlock;
6122
6123 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006124 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6125 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02006126 goto remove;
6127 }
6128
6129 cp = cmd->param;
6130
6131 switch (cp->val) {
6132 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006133 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
6134 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006135 break;
6136 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006137 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006138 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006139 break;
6140 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006141 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
6142 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006143 break;
6144 }
6145
6146 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
6147 new_settings(hdev, cmd->sk);
6148
6149remove:
6150 mgmt_pending_remove(cmd);
6151unlock:
6152 hci_dev_unlock(hdev);
6153}
6154
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006155static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
6156 void *data, u16 len)
6157{
6158 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006159 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02006160 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03006161 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006162 int err;
6163
Marcel Holtmann181d6952020-05-06 09:57:47 +02006164 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006165
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006166 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006167 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006168 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6169 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006170
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006171 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02006172 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006173 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6175 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08006176
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006177 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006178 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006179 MGMT_STATUS_INVALID_PARAMS);
6180
6181 hci_dev_lock(hdev);
6182
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006183 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006184 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006185 bool changed;
6186
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006187 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006188 changed = !hci_dev_test_and_set_flag(hdev,
6189 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006190 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006191 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006192 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006193 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006194 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006195 changed = hci_dev_test_and_clear_flag(hdev,
6196 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006197 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006198 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006199
6200 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6201 if (err < 0)
6202 goto failed;
6203
6204 if (changed)
6205 err = new_settings(hdev, sk);
6206
6207 goto failed;
6208 }
6209
Johan Hedberg333ae952015-03-17 13:48:47 +02006210 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006211 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6212 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006213 goto failed;
6214 }
6215
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006216 val = !!cp->val;
6217
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006218 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6219 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006220 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6221 goto failed;
6222 }
6223
6224 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
6225 if (!cmd) {
6226 err = -ENOMEM;
6227 goto failed;
6228 }
6229
Johan Hedberga1443f52015-01-23 15:42:46 +02006230 hci_req_init(&req, hdev);
6231 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
6232 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006233 if (err < 0) {
6234 mgmt_pending_remove(cmd);
6235 goto failed;
6236 }
6237
6238failed:
6239 hci_dev_unlock(hdev);
6240 return err;
6241}
6242
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006243static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
6244 void *data, u16 len)
6245{
6246 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03006247 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006248 int err;
6249
Marcel Holtmann181d6952020-05-06 09:57:47 +02006250 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006251
Johan Hedbergb97109792014-06-24 14:00:28 +03006252 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006253 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
6254 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006255
6256 hci_dev_lock(hdev);
6257
6258 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07006259 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006260 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006261 changed = hci_dev_test_and_clear_flag(hdev,
6262 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006263
Johan Hedbergb97109792014-06-24 14:00:28 +03006264 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07006265 use_changed = !hci_dev_test_and_set_flag(hdev,
6266 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006267 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006268 use_changed = hci_dev_test_and_clear_flag(hdev,
6269 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006270
6271 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006272 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03006273 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
6274 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
6275 sizeof(mode), &mode);
6276 }
6277
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006278 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
6279 if (err < 0)
6280 goto unlock;
6281
6282 if (changed)
6283 err = new_settings(hdev, sk);
6284
6285unlock:
6286 hci_dev_unlock(hdev);
6287 return err;
6288}
6289
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006290static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6291 u16 len)
6292{
6293 struct mgmt_cp_set_privacy *cp = cp_data;
6294 bool changed;
6295 int err;
6296
Marcel Holtmann181d6952020-05-06 09:57:47 +02006297 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006298
6299 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6301 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006302
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006303 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006304 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6305 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006306
6307 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6309 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006310
6311 hci_dev_lock(hdev);
6312
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006313 /* If user space supports this command it is also expected to
6314 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
6315 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006316 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006317
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006318 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006319 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006320 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006321 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306322 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006323 if (cp->privacy == 0x02)
6324 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
6325 else
6326 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006327 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006328 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006329 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006330 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306331 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006332 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006333 }
6334
6335 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
6336 if (err < 0)
6337 goto unlock;
6338
6339 if (changed)
6340 err = new_settings(hdev, sk);
6341
6342unlock:
6343 hci_dev_unlock(hdev);
6344 return err;
6345}
6346
Johan Hedberg41edf162014-02-18 10:19:35 +02006347static bool irk_is_valid(struct mgmt_irk_info *irk)
6348{
6349 switch (irk->addr.type) {
6350 case BDADDR_LE_PUBLIC:
6351 return true;
6352
6353 case BDADDR_LE_RANDOM:
6354 /* Two most significant bits shall be set */
6355 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6356 return false;
6357 return true;
6358 }
6359
6360 return false;
6361}
6362
6363static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6364 u16 len)
6365{
6366 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006367 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
6368 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02006369 u16 irk_count, expected_len;
6370 int i, err;
6371
Marcel Holtmann181d6952020-05-06 09:57:47 +02006372 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02006373
6374 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006375 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6376 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02006377
6378 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006379 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006380 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
6381 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006382 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6383 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006384 }
Johan Hedberg41edf162014-02-18 10:19:35 +02006385
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006386 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006387 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006388 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
6389 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006390 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6391 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006392 }
6393
Marcel Holtmann181d6952020-05-06 09:57:47 +02006394 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006395
6396 for (i = 0; i < irk_count; i++) {
6397 struct mgmt_irk_info *key = &cp->irks[i];
6398
6399 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006400 return mgmt_cmd_status(sk, hdev->id,
6401 MGMT_OP_LOAD_IRKS,
6402 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006403 }
6404
6405 hci_dev_lock(hdev);
6406
6407 hci_smp_irks_clear(hdev);
6408
6409 for (i = 0; i < irk_count; i++) {
6410 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02006411
Alain Michaud600a8742020-01-07 00:43:17 +00006412 if (hci_is_blocked_key(hdev,
6413 HCI_BLOCKED_KEY_TYPE_IRK,
6414 irk->val)) {
6415 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
6416 &irk->addr.bdaddr);
6417 continue;
6418 }
6419
Johan Hedberg85813a72015-10-21 18:02:59 +03006420 hci_add_irk(hdev, &irk->addr.bdaddr,
6421 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02006422 BDADDR_ANY);
6423 }
6424
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006425 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02006426
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006427 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02006428
6429 hci_dev_unlock(hdev);
6430
6431 return err;
6432}
6433
Johan Hedberg3f706b72013-01-20 14:27:16 +02006434static bool ltk_is_valid(struct mgmt_ltk_info *key)
6435{
Archie Pusakafad646e2021-05-31 16:37:25 +08006436 if (key->initiator != 0x00 && key->initiator != 0x01)
Johan Hedberg3f706b72013-01-20 14:27:16 +02006437 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08006438
6439 switch (key->addr.type) {
6440 case BDADDR_LE_PUBLIC:
6441 return true;
6442
6443 case BDADDR_LE_RANDOM:
6444 /* Two most significant bits shall be set */
6445 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6446 return false;
6447 return true;
6448 }
6449
6450 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02006451}
6452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006453static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006454 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006455{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006456 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006457 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
6458 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006459 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006460 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006461
Marcel Holtmann181d6952020-05-06 09:57:47 +02006462 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006463
6464 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006465 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6466 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006467
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006468 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006469 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006470 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
6471 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006472 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6473 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006474 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006475
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006476 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006477 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006478 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
6479 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006480 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6481 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006482 }
6483
Marcel Holtmann181d6952020-05-06 09:57:47 +02006484 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006485
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006486 for (i = 0; i < key_count; i++) {
6487 struct mgmt_ltk_info *key = &cp->keys[i];
6488
Johan Hedberg3f706b72013-01-20 14:27:16 +02006489 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006490 return mgmt_cmd_status(sk, hdev->id,
6491 MGMT_OP_LOAD_LONG_TERM_KEYS,
6492 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006493 }
6494
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006495 hci_dev_lock(hdev);
6496
6497 hci_smp_ltks_clear(hdev);
6498
6499 for (i = 0; i < key_count; i++) {
6500 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006501 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006502
Alain Michaud600a8742020-01-07 00:43:17 +00006503 if (hci_is_blocked_key(hdev,
6504 HCI_BLOCKED_KEY_TYPE_LTK,
6505 key->val)) {
6506 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6507 &key->addr.bdaddr);
6508 continue;
6509 }
6510
Johan Hedberg61b43352014-05-29 19:36:53 +03006511 switch (key->type) {
6512 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006513 authenticated = 0x00;
Archie Pusakafad646e2021-05-31 16:37:25 +08006514 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006515 break;
6516 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006517 authenticated = 0x01;
Archie Pusakafad646e2021-05-31 16:37:25 +08006518 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006519 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006520 case MGMT_LTK_P256_UNAUTH:
6521 authenticated = 0x00;
6522 type = SMP_LTK_P256;
6523 break;
6524 case MGMT_LTK_P256_AUTH:
6525 authenticated = 0x01;
6526 type = SMP_LTK_P256;
6527 break;
6528 case MGMT_LTK_P256_DEBUG:
6529 authenticated = 0x00;
6530 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006531 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006532 default:
6533 continue;
6534 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006535
Johan Hedberg85813a72015-10-21 18:02:59 +03006536 hci_add_ltk(hdev, &key->addr.bdaddr,
6537 le_addr_type(key->addr.type), type, authenticated,
6538 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006539 }
6540
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006541 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006542 NULL, 0);
6543
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006544 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006545
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006546 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006547}
6548
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006549static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006550{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006551 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006552 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006553 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006554
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006555 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006556
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006557 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006558 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006559 rp.tx_power = conn->tx_power;
6560 rp.max_tx_power = conn->max_tx_power;
6561 } else {
6562 rp.rssi = HCI_RSSI_INVALID;
6563 rp.tx_power = HCI_TX_POWER_INVALID;
6564 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006565 }
6566
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006567 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6568 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006569
6570 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006571 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006572
6573 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006574}
6575
Marcel Holtmann1904a852015-01-11 13:50:44 -08006576static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6577 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006578{
6579 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006580 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006581 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006582 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006583 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006584
Marcel Holtmann181d6952020-05-06 09:57:47 +02006585 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006586
6587 hci_dev_lock(hdev);
6588
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006589 /* Commands sent in request are either Read RSSI or Read Transmit Power
6590 * Level so we check which one was last sent to retrieve connection
6591 * handle. Both commands have handle as first parameter so it's safe to
6592 * cast data on the same command struct.
6593 *
6594 * First command sent is always Read RSSI and we fail only if it fails.
6595 * In other case we simply override error to indicate success as we
6596 * already remembered if TX power value is actually valid.
6597 */
6598 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6599 if (!cp) {
6600 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006601 status = MGMT_STATUS_SUCCESS;
6602 } else {
6603 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006604 }
6605
6606 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006607 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006608 goto unlock;
6609 }
6610
6611 handle = __le16_to_cpu(cp->handle);
6612 conn = hci_conn_hash_lookup_handle(hdev, handle);
6613 if (!conn) {
Kai Ye85d672842021-06-03 15:41:02 +08006614 bt_dev_err(hdev, "unknown handle (%u) in conn_info response",
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006615 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006616 goto unlock;
6617 }
6618
Johan Hedberg333ae952015-03-17 13:48:47 +02006619 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006620 if (!cmd)
6621 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006622
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006623 cmd->cmd_complete(cmd, status);
6624 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006625
6626unlock:
6627 hci_dev_unlock(hdev);
6628}
6629
6630static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6631 u16 len)
6632{
6633 struct mgmt_cp_get_conn_info *cp = data;
6634 struct mgmt_rp_get_conn_info rp;
6635 struct hci_conn *conn;
6636 unsigned long conn_info_age;
6637 int err = 0;
6638
Marcel Holtmann181d6952020-05-06 09:57:47 +02006639 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006640
6641 memset(&rp, 0, sizeof(rp));
6642 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6643 rp.addr.type = cp->addr.type;
6644
6645 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006646 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6647 MGMT_STATUS_INVALID_PARAMS,
6648 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006649
6650 hci_dev_lock(hdev);
6651
6652 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006653 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6654 MGMT_STATUS_NOT_POWERED, &rp,
6655 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006656 goto unlock;
6657 }
6658
6659 if (cp->addr.type == BDADDR_BREDR)
6660 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6661 &cp->addr.bdaddr);
6662 else
6663 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6664
6665 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006666 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6667 MGMT_STATUS_NOT_CONNECTED, &rp,
6668 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006669 goto unlock;
6670 }
6671
Johan Hedberg333ae952015-03-17 13:48:47 +02006672 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006673 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6674 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006675 goto unlock;
6676 }
6677
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006678 /* To avoid client trying to guess when to poll again for information we
6679 * calculate conn info age as random value between min/max set in hdev.
6680 */
6681 conn_info_age = hdev->conn_info_min_age +
6682 prandom_u32_max(hdev->conn_info_max_age -
6683 hdev->conn_info_min_age);
6684
6685 /* Query controller to refresh cached values if they are too old or were
6686 * never read.
6687 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006688 if (time_after(jiffies, conn->conn_info_timestamp +
6689 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006690 !conn->conn_info_timestamp) {
6691 struct hci_request req;
6692 struct hci_cp_read_tx_power req_txp_cp;
6693 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006694 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006695
6696 hci_req_init(&req, hdev);
6697 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6698 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6699 &req_rssi_cp);
6700
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006701 /* For LE links TX power does not change thus we don't need to
6702 * query for it once value is known.
6703 */
6704 if (!bdaddr_type_is_le(cp->addr.type) ||
6705 conn->tx_power == HCI_TX_POWER_INVALID) {
6706 req_txp_cp.handle = cpu_to_le16(conn->handle);
6707 req_txp_cp.type = 0x00;
6708 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6709 sizeof(req_txp_cp), &req_txp_cp);
6710 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006711
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006712 /* Max TX power needs to be read only once per connection */
6713 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6714 req_txp_cp.handle = cpu_to_le16(conn->handle);
6715 req_txp_cp.type = 0x01;
6716 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6717 sizeof(req_txp_cp), &req_txp_cp);
6718 }
6719
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006720 err = hci_req_run(&req, conn_info_refresh_complete);
6721 if (err < 0)
6722 goto unlock;
6723
6724 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6725 data, len);
6726 if (!cmd) {
6727 err = -ENOMEM;
6728 goto unlock;
6729 }
6730
6731 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006732 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006733 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006734
6735 conn->conn_info_timestamp = jiffies;
6736 } else {
6737 /* Cache is valid, just reply with values cached in hci_conn */
6738 rp.rssi = conn->rssi;
6739 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006740 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006741
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006742 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6743 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006744 }
6745
6746unlock:
6747 hci_dev_unlock(hdev);
6748 return err;
6749}
6750
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006751static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006752{
6753 struct hci_conn *conn = cmd->user_data;
6754 struct mgmt_rp_get_clock_info rp;
6755 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006756 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006757
6758 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006759 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006760
6761 if (status)
6762 goto complete;
6763
6764 hdev = hci_dev_get(cmd->index);
6765 if (hdev) {
6766 rp.local_clock = cpu_to_le32(hdev->clock);
6767 hci_dev_put(hdev);
6768 }
6769
6770 if (conn) {
6771 rp.piconet_clock = cpu_to_le32(conn->clock);
6772 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6773 }
6774
6775complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006776 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6777 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006778
6779 if (conn) {
6780 hci_conn_drop(conn);
6781 hci_conn_put(conn);
6782 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006783
6784 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006785}
6786
Marcel Holtmann1904a852015-01-11 13:50:44 -08006787static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006788{
Johan Hedberg95868422014-06-28 17:54:07 +03006789 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006790 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006791 struct hci_conn *conn;
6792
Marcel Holtmann181d6952020-05-06 09:57:47 +02006793 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006794
6795 hci_dev_lock(hdev);
6796
6797 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6798 if (!hci_cp)
6799 goto unlock;
6800
6801 if (hci_cp->which) {
6802 u16 handle = __le16_to_cpu(hci_cp->handle);
6803 conn = hci_conn_hash_lookup_handle(hdev, handle);
6804 } else {
6805 conn = NULL;
6806 }
6807
Johan Hedberg333ae952015-03-17 13:48:47 +02006808 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006809 if (!cmd)
6810 goto unlock;
6811
Johan Hedberg69487372014-12-05 13:36:07 +02006812 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006813 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006814
6815unlock:
6816 hci_dev_unlock(hdev);
6817}
6818
6819static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6820 u16 len)
6821{
6822 struct mgmt_cp_get_clock_info *cp = data;
6823 struct mgmt_rp_get_clock_info rp;
6824 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006825 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006826 struct hci_request req;
6827 struct hci_conn *conn;
6828 int err;
6829
Marcel Holtmann181d6952020-05-06 09:57:47 +02006830 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006831
6832 memset(&rp, 0, sizeof(rp));
6833 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6834 rp.addr.type = cp->addr.type;
6835
6836 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006837 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6838 MGMT_STATUS_INVALID_PARAMS,
6839 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006840
6841 hci_dev_lock(hdev);
6842
6843 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006844 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6845 MGMT_STATUS_NOT_POWERED, &rp,
6846 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006847 goto unlock;
6848 }
6849
6850 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6851 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6852 &cp->addr.bdaddr);
6853 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006854 err = mgmt_cmd_complete(sk, hdev->id,
6855 MGMT_OP_GET_CLOCK_INFO,
6856 MGMT_STATUS_NOT_CONNECTED,
6857 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006858 goto unlock;
6859 }
6860 } else {
6861 conn = NULL;
6862 }
6863
6864 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6865 if (!cmd) {
6866 err = -ENOMEM;
6867 goto unlock;
6868 }
6869
Johan Hedberg69487372014-12-05 13:36:07 +02006870 cmd->cmd_complete = clock_info_cmd_complete;
6871
Johan Hedberg95868422014-06-28 17:54:07 +03006872 hci_req_init(&req, hdev);
6873
6874 memset(&hci_cp, 0, sizeof(hci_cp));
6875 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6876
6877 if (conn) {
6878 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006879 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006880
6881 hci_cp.handle = cpu_to_le16(conn->handle);
6882 hci_cp.which = 0x01; /* Piconet clock */
6883 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6884 }
6885
6886 err = hci_req_run(&req, get_clock_info_complete);
6887 if (err < 0)
6888 mgmt_pending_remove(cmd);
6889
6890unlock:
6891 hci_dev_unlock(hdev);
6892 return err;
6893}
6894
Johan Hedberg5a154e62014-12-19 22:26:02 +02006895static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6896{
6897 struct hci_conn *conn;
6898
6899 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6900 if (!conn)
6901 return false;
6902
6903 if (conn->dst_type != type)
6904 return false;
6905
6906 if (conn->state != BT_CONNECTED)
6907 return false;
6908
6909 return true;
6910}
6911
6912/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006913static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006914 u8 addr_type, u8 auto_connect)
6915{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006916 struct hci_conn_params *params;
6917
6918 params = hci_conn_params_add(hdev, addr, addr_type);
6919 if (!params)
6920 return -EIO;
6921
6922 if (params->auto_connect == auto_connect)
6923 return 0;
6924
6925 list_del_init(&params->action);
6926
6927 switch (auto_connect) {
6928 case HCI_AUTO_CONN_DISABLED:
6929 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006930 /* If auto connect is being disabled when we're trying to
6931 * connect to device, keep connecting.
6932 */
6933 if (params->explicit_connect)
6934 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006935 break;
6936 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006937 if (params->explicit_connect)
6938 list_add(&params->action, &hdev->pend_le_conns);
6939 else
6940 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006941 break;
6942 case HCI_AUTO_CONN_DIRECT:
6943 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006944 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006945 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006946 break;
6947 }
6948
6949 params->auto_connect = auto_connect;
6950
Marcel Holtmann181d6952020-05-06 09:57:47 +02006951 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6952 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006953
6954 return 0;
6955}
6956
Marcel Holtmann8afef092014-06-29 22:28:34 +02006957static void device_added(struct sock *sk, struct hci_dev *hdev,
6958 bdaddr_t *bdaddr, u8 type, u8 action)
6959{
6960 struct mgmt_ev_device_added ev;
6961
6962 bacpy(&ev.addr.bdaddr, bdaddr);
6963 ev.addr.type = type;
6964 ev.action = action;
6965
6966 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6967}
6968
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07006969static int add_device_sync(struct hci_dev *hdev, void *data)
6970{
6971 return hci_update_passive_scan_sync(hdev);
6972}
6973
Marcel Holtmann2faade52014-06-29 19:44:03 +02006974static int add_device(struct sock *sk, struct hci_dev *hdev,
6975 void *data, u16 len)
6976{
6977 struct mgmt_cp_add_device *cp = data;
6978 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006979 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006980 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006981 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006982
Marcel Holtmann181d6952020-05-06 09:57:47 +02006983 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006984
Johan Hedberg66593582014-07-09 12:59:14 +03006985 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006986 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006987 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6988 MGMT_STATUS_INVALID_PARAMS,
6989 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006990
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006991 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006992 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6993 MGMT_STATUS_INVALID_PARAMS,
6994 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006995
6996 hci_dev_lock(hdev);
6997
Johan Hedberg66593582014-07-09 12:59:14 +03006998 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006999 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03007000 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007001 err = mgmt_cmd_complete(sk, hdev->id,
7002 MGMT_OP_ADD_DEVICE,
7003 MGMT_STATUS_INVALID_PARAMS,
7004 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007005 goto unlock;
7006 }
7007
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007008 err = hci_bdaddr_list_add_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02007009 &cp->addr.bdaddr,
7010 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03007011 if (err)
7012 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03007013
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007014 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007015
Johan Hedberg66593582014-07-09 12:59:14 +03007016 goto added;
7017 }
7018
Johan Hedberg85813a72015-10-21 18:02:59 +03007019 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007020
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007021 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02007022 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007023 else if (cp->action == 0x01)
7024 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007025 else
Johan Hedberga3451d22014-07-02 17:37:27 +03007026 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007027
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007028 /* Kernel internally uses conn_params with resolvable private
7029 * address, but Add Device allows only identity addresses.
7030 * Make sure it is enforced before calling
7031 * hci_conn_params_lookup.
7032 */
7033 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007034 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7035 MGMT_STATUS_INVALID_PARAMS,
7036 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007037 goto unlock;
7038 }
7039
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02007040 /* If the connection parameters don't exist for this device,
7041 * they will be created and configured with defaults.
7042 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02007043 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02007044 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007045 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7046 MGMT_STATUS_FAILED, &cp->addr,
7047 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007048 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007049 } else {
7050 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7051 addr_type);
7052 if (params)
7053 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007054 }
7055
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007056 err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
7057 if (err < 0)
7058 goto unlock;
Johan Hedberg51d7a942015-11-11 08:11:18 +02007059
Johan Hedberg66593582014-07-09 12:59:14 +03007060added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02007061 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007062 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
7063 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007064
Johan Hedberg51d7a942015-11-11 08:11:18 +02007065 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7066 MGMT_STATUS_SUCCESS, &cp->addr,
7067 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007068
7069unlock:
7070 hci_dev_unlock(hdev);
7071 return err;
7072}
7073
Marcel Holtmann8afef092014-06-29 22:28:34 +02007074static void device_removed(struct sock *sk, struct hci_dev *hdev,
7075 bdaddr_t *bdaddr, u8 type)
7076{
7077 struct mgmt_ev_device_removed ev;
7078
7079 bacpy(&ev.addr.bdaddr, bdaddr);
7080 ev.addr.type = type;
7081
7082 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
7083}
7084
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007085static int remove_device_sync(struct hci_dev *hdev, void *data)
7086{
7087 return hci_update_passive_scan_sync(hdev);
7088}
7089
Marcel Holtmann2faade52014-06-29 19:44:03 +02007090static int remove_device(struct sock *sk, struct hci_dev *hdev,
7091 void *data, u16 len)
7092{
7093 struct mgmt_cp_remove_device *cp = data;
7094 int err;
7095
Marcel Holtmann181d6952020-05-06 09:57:47 +02007096 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007097
7098 hci_dev_lock(hdev);
7099
7100 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03007101 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007102 u8 addr_type;
7103
Johan Hedberg66593582014-07-09 12:59:14 +03007104 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007105 err = mgmt_cmd_complete(sk, hdev->id,
7106 MGMT_OP_REMOVE_DEVICE,
7107 MGMT_STATUS_INVALID_PARAMS,
7108 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007109 goto unlock;
7110 }
7111
Johan Hedberg66593582014-07-09 12:59:14 +03007112 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007113 err = hci_bdaddr_list_del(&hdev->accept_list,
Johan Hedberg66593582014-07-09 12:59:14 +03007114 &cp->addr.bdaddr,
7115 cp->addr.type);
7116 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007117 err = mgmt_cmd_complete(sk, hdev->id,
7118 MGMT_OP_REMOVE_DEVICE,
7119 MGMT_STATUS_INVALID_PARAMS,
7120 &cp->addr,
7121 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007122 goto unlock;
7123 }
7124
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007125 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007126
Johan Hedberg66593582014-07-09 12:59:14 +03007127 device_removed(sk, hdev, &cp->addr.bdaddr,
7128 cp->addr.type);
7129 goto complete;
7130 }
7131
Johan Hedberg85813a72015-10-21 18:02:59 +03007132 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007133
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007134 /* Kernel internally uses conn_params with resolvable private
7135 * address, but Remove Device allows only identity addresses.
7136 * Make sure it is enforced before calling
7137 * hci_conn_params_lookup.
7138 */
7139 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007140 err = mgmt_cmd_complete(sk, hdev->id,
7141 MGMT_OP_REMOVE_DEVICE,
7142 MGMT_STATUS_INVALID_PARAMS,
7143 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007144 goto unlock;
7145 }
7146
Johan Hedbergc71593d2014-07-02 17:37:28 +03007147 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7148 addr_type);
7149 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007150 err = mgmt_cmd_complete(sk, hdev->id,
7151 MGMT_OP_REMOVE_DEVICE,
7152 MGMT_STATUS_INVALID_PARAMS,
7153 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007154 goto unlock;
7155 }
7156
Johan Hedberg679d2b62015-10-16 10:07:52 +03007157 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
7158 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007159 err = mgmt_cmd_complete(sk, hdev->id,
7160 MGMT_OP_REMOVE_DEVICE,
7161 MGMT_STATUS_INVALID_PARAMS,
7162 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007163 goto unlock;
7164 }
7165
Johan Hedbergd1dbf122014-07-04 16:17:23 +03007166 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03007167 list_del(&params->list);
7168 kfree(params);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007169
7170 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007171 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03007172 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03007173 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03007174
Marcel Holtmann2faade52014-06-29 19:44:03 +02007175 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007176 err = mgmt_cmd_complete(sk, hdev->id,
7177 MGMT_OP_REMOVE_DEVICE,
7178 MGMT_STATUS_INVALID_PARAMS,
7179 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007180 goto unlock;
7181 }
7182
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007183 list_for_each_entry_safe(b, btmp, &hdev->accept_list, list) {
Johan Hedberg66593582014-07-09 12:59:14 +03007184 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
7185 list_del(&b->list);
7186 kfree(b);
7187 }
7188
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007189 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007190
Johan Hedberg19de0822014-07-06 13:06:51 +03007191 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
7192 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
7193 continue;
7194 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03007195 if (p->explicit_connect) {
7196 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
7197 continue;
7198 }
Johan Hedberg19de0822014-07-06 13:06:51 +03007199 list_del(&p->action);
7200 list_del(&p->list);
7201 kfree(p);
7202 }
7203
Marcel Holtmann181d6952020-05-06 09:57:47 +02007204 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Marcel Holtmann2faade52014-06-29 19:44:03 +02007205 }
7206
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007207 hci_cmd_sync_queue(hdev, remove_device_sync, NULL, NULL);
7208
Johan Hedberg66593582014-07-09 12:59:14 +03007209complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02007210 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
7211 MGMT_STATUS_SUCCESS, &cp->addr,
7212 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007213unlock:
7214 hci_dev_unlock(hdev);
7215 return err;
7216}
7217
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007218static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
7219 u16 len)
7220{
7221 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03007222 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
7223 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007224 u16 param_count, expected_len;
7225 int i;
7226
7227 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007228 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7229 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007230
7231 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007232 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007233 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
7234 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02007235 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7236 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007237 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007238
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05007239 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007240 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007241 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
7242 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02007243 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7244 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007245 }
7246
Marcel Holtmann181d6952020-05-06 09:57:47 +02007247 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007248
7249 hci_dev_lock(hdev);
7250
7251 hci_conn_params_clear_disabled(hdev);
7252
7253 for (i = 0; i < param_count; i++) {
7254 struct mgmt_conn_param *param = &cp->params[i];
7255 struct hci_conn_params *hci_param;
7256 u16 min, max, latency, timeout;
7257 u8 addr_type;
7258
Marcel Holtmann181d6952020-05-06 09:57:47 +02007259 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
7260 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007261
7262 if (param->addr.type == BDADDR_LE_PUBLIC) {
7263 addr_type = ADDR_LE_DEV_PUBLIC;
7264 } else if (param->addr.type == BDADDR_LE_RANDOM) {
7265 addr_type = ADDR_LE_DEV_RANDOM;
7266 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007267 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007268 continue;
7269 }
7270
7271 min = le16_to_cpu(param->min_interval);
7272 max = le16_to_cpu(param->max_interval);
7273 latency = le16_to_cpu(param->latency);
7274 timeout = le16_to_cpu(param->timeout);
7275
Marcel Holtmann181d6952020-05-06 09:57:47 +02007276 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
7277 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007278
7279 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007280 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007281 continue;
7282 }
7283
7284 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
7285 addr_type);
7286 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007287 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007288 continue;
7289 }
7290
7291 hci_param->conn_min_interval = min;
7292 hci_param->conn_max_interval = max;
7293 hci_param->conn_latency = latency;
7294 hci_param->supervision_timeout = timeout;
7295 }
7296
7297 hci_dev_unlock(hdev);
7298
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007299 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
7300 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007301}
7302
Marcel Holtmanndbece372014-07-04 18:11:55 +02007303static int set_external_config(struct sock *sk, struct hci_dev *hdev,
7304 void *data, u16 len)
7305{
7306 struct mgmt_cp_set_external_config *cp = data;
7307 bool changed;
7308 int err;
7309
Marcel Holtmann181d6952020-05-06 09:57:47 +02007310 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007311
7312 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007313 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7314 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007315
7316 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02007317 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7318 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007319
7320 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02007321 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7322 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007323
7324 hci_dev_lock(hdev);
7325
7326 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07007327 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007328 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007329 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007330
7331 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
7332 if (err < 0)
7333 goto unlock;
7334
7335 if (!changed)
7336 goto unlock;
7337
Marcel Holtmannf4537c02014-07-04 19:06:23 +02007338 err = new_options(hdev, sk);
7339
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007340 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02007341 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007342
Marcel Holtmann516018a2015-03-13 02:11:04 -07007343 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007344 hci_dev_set_flag(hdev, HCI_CONFIG);
7345 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007346
7347 queue_work(hdev->req_workqueue, &hdev->power_on);
7348 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02007349 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007350 mgmt_index_added(hdev);
7351 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02007352 }
7353
7354unlock:
7355 hci_dev_unlock(hdev);
7356 return err;
7357}
7358
Marcel Holtmann9713c172014-07-06 12:11:15 +02007359static int set_public_address(struct sock *sk, struct hci_dev *hdev,
7360 void *data, u16 len)
7361{
7362 struct mgmt_cp_set_public_address *cp = data;
7363 bool changed;
7364 int err;
7365
Marcel Holtmann181d6952020-05-06 09:57:47 +02007366 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007367
7368 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007369 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7370 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007371
7372 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02007373 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7374 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007375
7376 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02007377 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7378 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007379
7380 hci_dev_lock(hdev);
7381
7382 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
7383 bacpy(&hdev->public_addr, &cp->bdaddr);
7384
7385 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
7386 if (err < 0)
7387 goto unlock;
7388
7389 if (!changed)
7390 goto unlock;
7391
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007392 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02007393 err = new_options(hdev, sk);
7394
7395 if (is_configured(hdev)) {
7396 mgmt_index_removed(hdev);
7397
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007398 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007399
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007400 hci_dev_set_flag(hdev, HCI_CONFIG);
7401 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007402
7403 queue_work(hdev->req_workqueue, &hdev->power_on);
7404 }
7405
7406unlock:
7407 hci_dev_unlock(hdev);
7408 return err;
7409}
7410
Johan Hedberg40f66c02015-04-07 21:52:22 +03007411static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
7412 u16 opcode, struct sk_buff *skb)
7413{
7414 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
7415 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
7416 u8 *h192, *r192, *h256, *r256;
7417 struct mgmt_pending_cmd *cmd;
7418 u16 eir_len;
7419 int err;
7420
Marcel Holtmann181d6952020-05-06 09:57:47 +02007421 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007422
7423 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
7424 if (!cmd)
7425 return;
7426
7427 mgmt_cp = cmd->param;
7428
7429 if (status) {
7430 status = mgmt_status(status);
7431 eir_len = 0;
7432
7433 h192 = NULL;
7434 r192 = NULL;
7435 h256 = NULL;
7436 r256 = NULL;
7437 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
7438 struct hci_rp_read_local_oob_data *rp;
7439
7440 if (skb->len != sizeof(*rp)) {
7441 status = MGMT_STATUS_FAILED;
7442 eir_len = 0;
7443 } else {
7444 status = MGMT_STATUS_SUCCESS;
7445 rp = (void *)skb->data;
7446
7447 eir_len = 5 + 18 + 18;
7448 h192 = rp->hash;
7449 r192 = rp->rand;
7450 h256 = NULL;
7451 r256 = NULL;
7452 }
7453 } else {
7454 struct hci_rp_read_local_oob_ext_data *rp;
7455
7456 if (skb->len != sizeof(*rp)) {
7457 status = MGMT_STATUS_FAILED;
7458 eir_len = 0;
7459 } else {
7460 status = MGMT_STATUS_SUCCESS;
7461 rp = (void *)skb->data;
7462
7463 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
7464 eir_len = 5 + 18 + 18;
7465 h192 = NULL;
7466 r192 = NULL;
7467 } else {
7468 eir_len = 5 + 18 + 18 + 18 + 18;
7469 h192 = rp->hash192;
7470 r192 = rp->rand192;
7471 }
7472
7473 h256 = rp->hash256;
7474 r256 = rp->rand256;
7475 }
7476 }
7477
7478 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
7479 if (!mgmt_rp)
7480 goto done;
7481
Kees Cooka31e5a42021-08-17 21:39:12 -07007482 if (eir_len == 0)
Johan Hedberg40f66c02015-04-07 21:52:22 +03007483 goto send_rsp;
7484
7485 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
7486 hdev->dev_class, 3);
7487
7488 if (h192 && r192) {
7489 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7490 EIR_SSP_HASH_C192, h192, 16);
7491 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7492 EIR_SSP_RAND_R192, r192, 16);
7493 }
7494
7495 if (h256 && r256) {
7496 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7497 EIR_SSP_HASH_C256, h256, 16);
7498 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7499 EIR_SSP_RAND_R256, r256, 16);
7500 }
7501
7502send_rsp:
7503 mgmt_rp->type = mgmt_cp->type;
7504 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7505
7506 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7507 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7508 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7509 if (err < 0 || status)
7510 goto done;
7511
7512 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7513
7514 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7515 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7516 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7517done:
7518 kfree(mgmt_rp);
7519 mgmt_pending_remove(cmd);
7520}
7521
7522static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7523 struct mgmt_cp_read_local_oob_ext_data *cp)
7524{
7525 struct mgmt_pending_cmd *cmd;
7526 struct hci_request req;
7527 int err;
7528
7529 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7530 cp, sizeof(*cp));
7531 if (!cmd)
7532 return -ENOMEM;
7533
7534 hci_req_init(&req, hdev);
7535
7536 if (bredr_sc_enabled(hdev))
7537 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7538 else
7539 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7540
7541 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7542 if (err < 0) {
7543 mgmt_pending_remove(cmd);
7544 return err;
7545 }
7546
7547 return 0;
7548}
7549
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007550static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7551 void *data, u16 data_len)
7552{
7553 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7554 struct mgmt_rp_read_local_oob_ext_data *rp;
7555 size_t rp_len;
7556 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007557 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007558 int err;
7559
Marcel Holtmann181d6952020-05-06 09:57:47 +02007560 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007561
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007562 if (hdev_is_powered(hdev)) {
7563 switch (cp->type) {
7564 case BIT(BDADDR_BREDR):
7565 status = mgmt_bredr_support(hdev);
7566 if (status)
7567 eir_len = 0;
7568 else
7569 eir_len = 5;
7570 break;
7571 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7572 status = mgmt_le_support(hdev);
7573 if (status)
7574 eir_len = 0;
7575 else
7576 eir_len = 9 + 3 + 18 + 18 + 3;
7577 break;
7578 default:
7579 status = MGMT_STATUS_INVALID_PARAMS;
7580 eir_len = 0;
7581 break;
7582 }
7583 } else {
7584 status = MGMT_STATUS_NOT_POWERED;
7585 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007586 }
7587
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007588 rp_len = sizeof(*rp) + eir_len;
7589 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007590 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007591 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007592
Brian Gix81218cb2021-08-23 14:57:29 -07007593 if (!status && !lmp_ssp_capable(hdev)) {
7594 status = MGMT_STATUS_NOT_SUPPORTED;
7595 eir_len = 0;
7596 }
7597
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007598 if (status)
7599 goto complete;
7600
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007601 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007602
7603 eir_len = 0;
7604 switch (cp->type) {
7605 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007606 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7607 err = read_local_ssp_oob_req(hdev, sk, cp);
7608 hci_dev_unlock(hdev);
7609 if (!err)
7610 goto done;
7611
7612 status = MGMT_STATUS_FAILED;
7613 goto complete;
7614 } else {
7615 eir_len = eir_append_data(rp->eir, eir_len,
7616 EIR_CLASS_OF_DEV,
7617 hdev->dev_class, 3);
7618 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007619 break;
7620 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007621 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7622 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007623 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007624 status = MGMT_STATUS_FAILED;
7625 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007626 }
7627
Marcel Holtmanne2135682015-04-02 12:00:58 -07007628 /* This should return the active RPA, but since the RPA
7629 * is only programmed on demand, it is really hard to fill
7630 * this in at the moment. For now disallow retrieving
7631 * local out-of-band data when privacy is in use.
7632 *
7633 * Returning the identity address will not help here since
7634 * pairing happens before the identity resolving key is
7635 * known and thus the connection establishment happens
7636 * based on the RPA and not the identity address.
7637 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007638 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007639 hci_dev_unlock(hdev);
7640 status = MGMT_STATUS_REJECTED;
7641 goto complete;
7642 }
7643
7644 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7645 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7646 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7647 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007648 memcpy(addr, &hdev->static_addr, 6);
7649 addr[6] = 0x01;
7650 } else {
7651 memcpy(addr, &hdev->bdaddr, 6);
7652 addr[6] = 0x00;
7653 }
7654
7655 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7656 addr, sizeof(addr));
7657
7658 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7659 role = 0x02;
7660 else
7661 role = 0x01;
7662
7663 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7664 &role, sizeof(role));
7665
Marcel Holtmann5082a592015-03-16 12:39:00 -07007666 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7667 eir_len = eir_append_data(rp->eir, eir_len,
7668 EIR_LE_SC_CONFIRM,
7669 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007670
Marcel Holtmann5082a592015-03-16 12:39:00 -07007671 eir_len = eir_append_data(rp->eir, eir_len,
7672 EIR_LE_SC_RANDOM,
7673 rand, sizeof(rand));
7674 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007675
Johan Hedbergf2252572015-11-18 12:49:20 +02007676 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007677
7678 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7679 flags |= LE_AD_NO_BREDR;
7680
7681 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7682 &flags, sizeof(flags));
7683 break;
7684 }
7685
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007686 hci_dev_unlock(hdev);
7687
Marcel Holtmann72000df2015-03-16 16:11:21 -07007688 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7689
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007690 status = MGMT_STATUS_SUCCESS;
7691
7692complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007693 rp->type = cp->type;
7694 rp->eir_len = cpu_to_le16(eir_len);
7695
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007696 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007697 status, rp, sizeof(*rp) + eir_len);
7698 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007699 goto done;
7700
7701 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7702 rp, sizeof(*rp) + eir_len,
7703 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007704
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007705done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007706 kfree(rp);
7707
7708 return err;
7709}
7710
Arman Uguray089fa8c2015-03-25 18:53:45 -07007711static u32 get_supported_adv_flags(struct hci_dev *hdev)
7712{
7713 u32 flags = 0;
7714
7715 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7716 flags |= MGMT_ADV_FLAG_DISCOV;
7717 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7718 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007719 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007720 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Daniel Winkler12410572020-12-03 12:12:49 -08007721 flags |= MGMT_ADV_PARAM_DURATION;
7722 flags |= MGMT_ADV_PARAM_TIMEOUT;
7723 flags |= MGMT_ADV_PARAM_INTERVALS;
7724 flags |= MGMT_ADV_PARAM_TX_POWER;
Daniel Winklerff02db12021-03-03 11:15:23 -08007725 flags |= MGMT_ADV_PARAM_SCAN_RSP;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007726
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307727 /* In extended adv TX_POWER returned from Set Adv Param
7728 * will be always valid.
7729 */
7730 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7731 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007732 flags |= MGMT_ADV_FLAG_TX_POWER;
7733
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307734 if (ext_adv_capable(hdev)) {
7735 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007736 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7737 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307738
7739 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7740 flags |= MGMT_ADV_FLAG_SEC_2M;
7741
7742 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7743 flags |= MGMT_ADV_FLAG_SEC_CODED;
7744 }
7745
Arman Uguray089fa8c2015-03-25 18:53:45 -07007746 return flags;
7747}
7748
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007749static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7750 void *data, u16 data_len)
7751{
7752 struct mgmt_rp_read_adv_features *rp;
7753 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007754 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007755 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007756 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007757 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007758
Marcel Holtmann181d6952020-05-06 09:57:47 +02007759 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007760
Arman Uguray089fa8c2015-03-25 18:53:45 -07007761 if (!lmp_le_capable(hdev))
7762 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7763 MGMT_STATUS_REJECTED);
7764
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007765 hci_dev_lock(hdev);
7766
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007767 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007768 rp = kmalloc(rp_len, GFP_ATOMIC);
7769 if (!rp) {
7770 hci_dev_unlock(hdev);
7771 return -ENOMEM;
7772 }
7773
Arman Uguray089fa8c2015-03-25 18:53:45 -07007774 supported_flags = get_supported_adv_flags(hdev);
7775
7776 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007777 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7778 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007779 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007780 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007781
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007782 instance = rp->instance;
7783 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7784 *instance = adv_instance->instance;
7785 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007786 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007787
7788 hci_dev_unlock(hdev);
7789
7790 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7791 MGMT_STATUS_SUCCESS, rp, rp_len);
7792
7793 kfree(rp);
7794
7795 return err;
7796}
7797
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007798static u8 calculate_name_len(struct hci_dev *hdev)
7799{
7800 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7801
Luiz Augusto von Dentz01ce70b2021-09-20 15:59:37 -07007802 return eir_append_local_name(hdev, buf, 0);
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007803}
7804
7805static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7806 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007807{
Arman Uguray4117ed72015-03-23 15:57:14 -07007808 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007809
Marcel Holtmann31a32482015-11-19 16:16:42 +01007810 if (is_adv_data) {
7811 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7812 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007813 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007814 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007815
Szymon Janc2bb368702016-09-18 12:50:05 +02007816 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007817 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007818 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007819 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007820 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007821
Szymon Janc2bb368702016-09-18 12:50:05 +02007822 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007823 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007824 }
7825
Szymon Janc2bb368702016-09-18 12:50:05 +02007826 return max_len;
7827}
7828
7829static bool flags_managed(u32 adv_flags)
7830{
7831 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7832 MGMT_ADV_FLAG_LIMITED_DISCOV |
7833 MGMT_ADV_FLAG_MANAGED_FLAGS);
7834}
7835
7836static bool tx_power_managed(u32 adv_flags)
7837{
7838 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7839}
7840
7841static bool name_managed(u32 adv_flags)
7842{
7843 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7844}
7845
7846static bool appearance_managed(u32 adv_flags)
7847{
7848 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7849}
7850
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007851static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7852 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007853{
7854 int i, cur_len;
7855 u8 max_len;
7856
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007857 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007858
Arman Uguray4117ed72015-03-23 15:57:14 -07007859 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007860 return false;
7861
Arman Uguray4117ed72015-03-23 15:57:14 -07007862 /* Make sure that the data is correctly formatted. */
7863 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7864 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007865
Luiz Augusto von Dentz799acb92021-05-28 11:45:02 -07007866 if (!cur_len)
7867 continue;
7868
Szymon Janc9c9db782016-09-18 12:50:06 +02007869 if (data[i + 1] == EIR_FLAGS &&
7870 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007871 return false;
7872
Szymon Janc2bb368702016-09-18 12:50:05 +02007873 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7874 return false;
7875
7876 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7877 return false;
7878
7879 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7880 return false;
7881
7882 if (data[i + 1] == EIR_APPEARANCE &&
7883 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007884 return false;
7885
Arman Uguray24b4f382015-03-23 15:57:12 -07007886 /* If the current field length would exceed the total data
7887 * length, then it's invalid.
7888 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007889 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007890 return false;
7891 }
7892
7893 return true;
7894}
7895
Daniel Winkler12410572020-12-03 12:12:49 -08007896static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
7897{
7898 u32 supported_flags, phy_flags;
7899
7900 /* The current implementation only supports a subset of the specified
7901 * flags. Also need to check mutual exclusiveness of sec flags.
7902 */
7903 supported_flags = get_supported_adv_flags(hdev);
7904 phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK;
7905 if (adv_flags & ~supported_flags ||
7906 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
7907 return false;
7908
7909 return true;
7910}
7911
7912static bool adv_busy(struct hci_dev *hdev)
7913{
7914 return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7915 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7916 pending_find(MGMT_OP_SET_LE, hdev) ||
7917 pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
7918 pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
7919}
7920
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007921static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
7922 int err)
Arman Uguray24b4f382015-03-23 15:57:12 -07007923{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007924 struct adv_info *adv, *n;
Arman Uguray24b4f382015-03-23 15:57:12 -07007925
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007926 bt_dev_dbg(hdev, "err %d", err);
Arman Uguray24b4f382015-03-23 15:57:12 -07007927
7928 hci_dev_lock(hdev);
7929
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007930 list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
7931 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007932
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007933 if (!adv->pending)
Florian Grandelfffd38b2015-06-18 03:16:47 +02007934 continue;
7935
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007936 if (!err) {
7937 adv->pending = false;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007938 continue;
7939 }
7940
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007941 instance = adv->instance;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007942
7943 if (hdev->cur_adv_instance == instance)
7944 cancel_adv_timeout(hdev);
7945
7946 hci_remove_adv_instance(hdev, instance);
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007947 mgmt_advertising_removed(sk, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007948 }
7949
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007950 hci_dev_unlock(hdev);
7951}
Arman Uguray24b4f382015-03-23 15:57:12 -07007952
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007953static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
7954{
7955 struct mgmt_pending_cmd *cmd = data;
7956 struct mgmt_cp_add_advertising *cp = cmd->param;
7957 struct mgmt_rp_add_advertising rp;
7958
7959 memset(&rp, 0, sizeof(rp));
7960
Florian Grandelfffd38b2015-06-18 03:16:47 +02007961 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007962
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007963 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07007964 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007965 mgmt_status(err));
Arman Uguray24b4f382015-03-23 15:57:12 -07007966 else
7967 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007968 mgmt_status(err), &rp, sizeof(rp));
Arman Uguray24b4f382015-03-23 15:57:12 -07007969
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007970 add_adv_complete(hdev, cmd->sk, cp->instance, err);
Arman Uguray24b4f382015-03-23 15:57:12 -07007971
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007972 mgmt_pending_free(cmd);
7973}
7974
7975static int add_advertising_sync(struct hci_dev *hdev, void *data)
7976{
7977 struct mgmt_pending_cmd *cmd = data;
7978 struct mgmt_cp_add_advertising *cp = cmd->param;
7979
7980 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007981}
7982
7983static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7984 void *data, u16 data_len)
7985{
7986 struct mgmt_cp_add_advertising *cp = data;
7987 struct mgmt_rp_add_advertising rp;
7988 u32 flags;
7989 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007990 u16 timeout, duration;
7991 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7992 u8 schedule_instance = 0;
7993 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007994 int err;
7995 struct mgmt_pending_cmd *cmd;
Arman Uguray24b4f382015-03-23 15:57:12 -07007996
Marcel Holtmann181d6952020-05-06 09:57:47 +02007997 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007998
7999 status = mgmt_le_support(hdev);
8000 if (status)
8001 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8002 status);
8003
Daniel Winkler87597482020-08-25 16:31:50 -07008004 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01008005 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8006 MGMT_STATUS_INVALID_PARAMS);
8007
Johan Hedberg6a0e7802016-03-11 09:56:33 +02008008 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
8009 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8010 MGMT_STATUS_INVALID_PARAMS);
8011
Arman Uguray24b4f382015-03-23 15:57:12 -07008012 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07008013 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008014 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07008015
Daniel Winkler12410572020-12-03 12:12:49 -08008016 if (!requested_adv_flags_are_valid(hdev, flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07008017 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8018 MGMT_STATUS_INVALID_PARAMS);
8019
8020 hci_dev_lock(hdev);
8021
Arman Uguray912098a2015-03-23 15:57:15 -07008022 if (timeout && !hdev_is_powered(hdev)) {
8023 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8024 MGMT_STATUS_REJECTED);
8025 goto unlock;
8026 }
8027
Daniel Winkler12410572020-12-03 12:12:49 -08008028 if (adv_busy(hdev)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008029 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8030 MGMT_STATUS_BUSY);
8031 goto unlock;
8032 }
8033
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008034 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
8035 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07008036 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008037 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8038 MGMT_STATUS_INVALID_PARAMS);
8039 goto unlock;
8040 }
8041
Florian Grandelfffd38b2015-06-18 03:16:47 +02008042 err = hci_add_adv_instance(hdev, cp->instance, flags,
8043 cp->adv_data_len, cp->data,
8044 cp->scan_rsp_len,
8045 cp->data + cp->adv_data_len,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008046 timeout, duration,
8047 HCI_ADV_TX_POWER_NO_PREFERENCE,
8048 hdev->le_adv_min_interval,
8049 hdev->le_adv_max_interval);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008050 if (err < 0) {
8051 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8052 MGMT_STATUS_FAILED);
8053 goto unlock;
8054 }
Arman Uguray24b4f382015-03-23 15:57:12 -07008055
Florian Grandelfffd38b2015-06-18 03:16:47 +02008056 /* Only trigger an advertising added event if a new instance was
8057 * actually added.
8058 */
8059 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02008060 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07008061
Florian Grandelfffd38b2015-06-18 03:16:47 +02008062 if (hdev->cur_adv_instance == cp->instance) {
8063 /* If the currently advertised instance is being changed then
8064 * cancel the current advertising and schedule the next
8065 * instance. If there is only one instance then the overridden
8066 * advertising data will be visible right away.
8067 */
8068 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07008069
Florian Grandelfffd38b2015-06-18 03:16:47 +02008070 next_instance = hci_get_next_instance(hdev, cp->instance);
8071 if (next_instance)
8072 schedule_instance = next_instance->instance;
8073 } else if (!hdev->adv_instance_timeout) {
8074 /* Immediately advertise the new instance if no other
8075 * instance is currently being advertised.
8076 */
8077 schedule_instance = cp->instance;
8078 }
Arman Uguray912098a2015-03-23 15:57:15 -07008079
Florian Grandelfffd38b2015-06-18 03:16:47 +02008080 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
8081 * there is no instance to be advertised then we have no HCI
8082 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07008083 */
8084 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02008085 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
8086 !schedule_instance) {
8087 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008088 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8089 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8090 goto unlock;
8091 }
8092
8093 /* We're good to go, update advertising data, parameters, and start
8094 * advertising.
8095 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008096 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
Arman Uguray24b4f382015-03-23 15:57:12 -07008097 data_len);
8098 if (!cmd) {
8099 err = -ENOMEM;
8100 goto unlock;
8101 }
8102
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008103 cp->instance = schedule_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008104
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008105 err = hci_cmd_sync_queue(hdev, add_advertising_sync, cmd,
8106 add_advertising_complete);
8107 if (err < 0)
8108 mgmt_pending_free(cmd);
Arman Uguray24b4f382015-03-23 15:57:12 -07008109
8110unlock:
8111 hci_dev_unlock(hdev);
8112
8113 return err;
8114}
8115
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008116static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
8117 int err)
Daniel Winkler12410572020-12-03 12:12:49 -08008118{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008119 struct mgmt_pending_cmd *cmd = data;
8120 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
Daniel Winkler12410572020-12-03 12:12:49 -08008121 struct mgmt_rp_add_ext_adv_params rp;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008122 struct adv_info *adv;
Daniel Winkler12410572020-12-03 12:12:49 -08008123 u32 flags;
8124
8125 BT_DBG("%s", hdev->name);
8126
8127 hci_dev_lock(hdev);
8128
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008129 adv = hci_find_adv_instance(hdev, cp->instance);
8130 if (!adv)
Daniel Winkler12410572020-12-03 12:12:49 -08008131 goto unlock;
8132
8133 rp.instance = cp->instance;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008134 rp.tx_power = adv->tx_power;
Daniel Winkler12410572020-12-03 12:12:49 -08008135
8136 /* While we're at it, inform userspace of the available space for this
8137 * advertisement, given the flags that will be used.
8138 */
8139 flags = __le32_to_cpu(cp->flags);
8140 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8141 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8142
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008143 if (err) {
Daniel Winkler12410572020-12-03 12:12:49 -08008144 /* If this advertisement was previously advertising and we
8145 * failed to update it, we signal that it has been removed and
8146 * delete its structure
8147 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008148 if (!adv->pending)
Daniel Winkler12410572020-12-03 12:12:49 -08008149 mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
8150
8151 hci_remove_adv_instance(hdev, cp->instance);
8152
8153 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008154 mgmt_status(err));
Daniel Winkler12410572020-12-03 12:12:49 -08008155 } else {
8156 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008157 mgmt_status(err), &rp, sizeof(rp));
Daniel Winkler12410572020-12-03 12:12:49 -08008158 }
8159
8160unlock:
8161 if (cmd)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008162 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008163
8164 hci_dev_unlock(hdev);
8165}
8166
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008167static int add_ext_adv_params_sync(struct hci_dev *hdev, void *data)
8168{
8169 struct mgmt_pending_cmd *cmd = data;
8170 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
8171
8172 return hci_setup_ext_adv_instance_sync(hdev, cp->instance);
8173}
8174
Daniel Winkler12410572020-12-03 12:12:49 -08008175static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
8176 void *data, u16 data_len)
8177{
8178 struct mgmt_cp_add_ext_adv_params *cp = data;
8179 struct mgmt_rp_add_ext_adv_params rp;
8180 struct mgmt_pending_cmd *cmd = NULL;
Daniel Winkler12410572020-12-03 12:12:49 -08008181 u32 flags, min_interval, max_interval;
8182 u16 timeout, duration;
8183 u8 status;
8184 s8 tx_power;
8185 int err;
8186
8187 BT_DBG("%s", hdev->name);
8188
8189 status = mgmt_le_support(hdev);
8190 if (status)
8191 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8192 status);
8193
8194 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
8195 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8196 MGMT_STATUS_INVALID_PARAMS);
8197
8198 /* The purpose of breaking add_advertising into two separate MGMT calls
8199 * for params and data is to allow more parameters to be added to this
8200 * structure in the future. For this reason, we verify that we have the
8201 * bare minimum structure we know of when the interface was defined. Any
8202 * extra parameters we don't know about will be ignored in this request.
8203 */
8204 if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE)
8205 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8206 MGMT_STATUS_INVALID_PARAMS);
8207
8208 flags = __le32_to_cpu(cp->flags);
8209
8210 if (!requested_adv_flags_are_valid(hdev, flags))
8211 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8212 MGMT_STATUS_INVALID_PARAMS);
8213
8214 hci_dev_lock(hdev);
8215
8216 /* In new interface, we require that we are powered to register */
8217 if (!hdev_is_powered(hdev)) {
8218 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8219 MGMT_STATUS_REJECTED);
8220 goto unlock;
8221 }
8222
8223 if (adv_busy(hdev)) {
8224 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8225 MGMT_STATUS_BUSY);
8226 goto unlock;
8227 }
8228
8229 /* Parse defined parameters from request, use defaults otherwise */
8230 timeout = (flags & MGMT_ADV_PARAM_TIMEOUT) ?
8231 __le16_to_cpu(cp->timeout) : 0;
8232
8233 duration = (flags & MGMT_ADV_PARAM_DURATION) ?
8234 __le16_to_cpu(cp->duration) :
8235 hdev->def_multi_adv_rotation_duration;
8236
8237 min_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8238 __le32_to_cpu(cp->min_interval) :
8239 hdev->le_adv_min_interval;
8240
8241 max_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8242 __le32_to_cpu(cp->max_interval) :
8243 hdev->le_adv_max_interval;
8244
8245 tx_power = (flags & MGMT_ADV_PARAM_TX_POWER) ?
8246 cp->tx_power :
8247 HCI_ADV_TX_POWER_NO_PREFERENCE;
8248
8249 /* Create advertising instance with no advertising or response data */
8250 err = hci_add_adv_instance(hdev, cp->instance, flags,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008251 0, NULL, 0, NULL, timeout, duration,
8252 tx_power, min_interval, max_interval);
Daniel Winkler12410572020-12-03 12:12:49 -08008253
8254 if (err < 0) {
8255 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8256 MGMT_STATUS_FAILED);
8257 goto unlock;
8258 }
8259
Daniel Winkler12410572020-12-03 12:12:49 -08008260 /* Submit request for advertising params if ext adv available */
8261 if (ext_adv_capable(hdev)) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008262 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev,
8263 data, data_len);
Daniel Winkler12410572020-12-03 12:12:49 -08008264 if (!cmd) {
8265 err = -ENOMEM;
8266 hci_remove_adv_instance(hdev, cp->instance);
8267 goto unlock;
8268 }
8269
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008270 err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd,
8271 add_ext_adv_params_complete);
8272 if (err < 0)
8273 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008274 } else {
8275 rp.instance = cp->instance;
8276 rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
8277 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8278 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8279 err = mgmt_cmd_complete(sk, hdev->id,
8280 MGMT_OP_ADD_EXT_ADV_PARAMS,
8281 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8282 }
8283
8284unlock:
8285 hci_dev_unlock(hdev);
8286
8287 return err;
8288}
8289
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008290static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
8291{
8292 struct mgmt_pending_cmd *cmd = data;
8293 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8294 struct mgmt_rp_add_advertising rp;
8295
8296 add_adv_complete(hdev, cmd->sk, cp->instance, err);
8297
8298 memset(&rp, 0, sizeof(rp));
8299
8300 rp.instance = cp->instance;
8301
8302 if (err)
8303 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8304 mgmt_status(err));
8305 else
8306 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8307 mgmt_status(err), &rp, sizeof(rp));
8308
8309 mgmt_pending_free(cmd);
8310}
8311
8312static int add_ext_adv_data_sync(struct hci_dev *hdev, void *data)
8313{
8314 struct mgmt_pending_cmd *cmd = data;
8315 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8316 int err;
8317
8318 if (ext_adv_capable(hdev)) {
8319 err = hci_update_adv_data_sync(hdev, cp->instance);
8320 if (err)
8321 return err;
8322
8323 err = hci_update_scan_rsp_data_sync(hdev, cp->instance);
8324 if (err)
8325 return err;
8326
8327 return hci_enable_ext_advertising_sync(hdev, cp->instance);
8328 }
8329
8330 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
8331}
8332
Daniel Winkler12410572020-12-03 12:12:49 -08008333static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
8334 u16 data_len)
8335{
8336 struct mgmt_cp_add_ext_adv_data *cp = data;
8337 struct mgmt_rp_add_ext_adv_data rp;
8338 u8 schedule_instance = 0;
8339 struct adv_info *next_instance;
8340 struct adv_info *adv_instance;
8341 int err = 0;
8342 struct mgmt_pending_cmd *cmd;
Daniel Winkler12410572020-12-03 12:12:49 -08008343
8344 BT_DBG("%s", hdev->name);
8345
8346 hci_dev_lock(hdev);
8347
8348 adv_instance = hci_find_adv_instance(hdev, cp->instance);
8349
8350 if (!adv_instance) {
8351 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8352 MGMT_STATUS_INVALID_PARAMS);
8353 goto unlock;
8354 }
8355
8356 /* In new interface, we require that we are powered to register */
8357 if (!hdev_is_powered(hdev)) {
8358 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8359 MGMT_STATUS_REJECTED);
8360 goto clear_new_instance;
8361 }
8362
8363 if (adv_busy(hdev)) {
8364 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8365 MGMT_STATUS_BUSY);
8366 goto clear_new_instance;
8367 }
8368
8369 /* Validate new data */
8370 if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data,
8371 cp->adv_data_len, true) ||
8372 !tlv_data_is_valid(hdev, adv_instance->flags, cp->data +
8373 cp->adv_data_len, cp->scan_rsp_len, false)) {
8374 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8375 MGMT_STATUS_INVALID_PARAMS);
8376 goto clear_new_instance;
8377 }
8378
8379 /* Set the data in the advertising instance */
8380 hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len,
8381 cp->data, cp->scan_rsp_len,
8382 cp->data + cp->adv_data_len);
8383
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008384 /* If using software rotation, determine next instance to use */
8385 if (hdev->cur_adv_instance == cp->instance) {
8386 /* If the currently advertised instance is being changed
8387 * then cancel the current advertising and schedule the
8388 * next instance. If there is only one instance then the
8389 * overridden advertising data will be visible right
8390 * away
Daniel Winkler12410572020-12-03 12:12:49 -08008391 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008392 cancel_adv_timeout(hdev);
Daniel Winkler12410572020-12-03 12:12:49 -08008393
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008394 next_instance = hci_get_next_instance(hdev, cp->instance);
8395 if (next_instance)
8396 schedule_instance = next_instance->instance;
8397 } else if (!hdev->adv_instance_timeout) {
8398 /* Immediately advertise the new instance if no other
8399 * instance is currently being advertised.
8400 */
8401 schedule_instance = cp->instance;
Daniel Winkler12410572020-12-03 12:12:49 -08008402 }
8403
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008404 /* If the HCI_ADVERTISING flag is set or there is no instance to
8405 * be advertised then we have no HCI communication to make.
8406 * Simply return.
8407 */
8408 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) {
8409 if (adv_instance->pending) {
8410 mgmt_advertising_added(sk, hdev, cp->instance);
8411 adv_instance->pending = false;
8412 }
8413 rp.instance = cp->instance;
8414 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8415 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8416 goto unlock;
8417 }
8418
8419 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
Daniel Winkler12410572020-12-03 12:12:49 -08008420 data_len);
8421 if (!cmd) {
8422 err = -ENOMEM;
8423 goto clear_new_instance;
8424 }
8425
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008426 err = hci_cmd_sync_queue(hdev, add_ext_adv_data_sync, cmd,
8427 add_ext_adv_data_complete);
Daniel Winkler12410572020-12-03 12:12:49 -08008428 if (err < 0) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008429 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008430 goto clear_new_instance;
8431 }
8432
8433 /* We were successful in updating data, so trigger advertising_added
8434 * event if this is an instance that wasn't previously advertising. If
8435 * a failure occurs in the requests we initiated, we will remove the
8436 * instance again in add_advertising_complete
8437 */
8438 if (adv_instance->pending)
8439 mgmt_advertising_added(sk, hdev, cp->instance);
8440
8441 goto unlock;
8442
8443clear_new_instance:
8444 hci_remove_adv_instance(hdev, cp->instance);
8445
8446unlock:
8447 hci_dev_unlock(hdev);
8448
8449 return err;
8450}
8451
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008452static void remove_advertising_complete(struct hci_dev *hdev, void *data,
8453 int err)
Arman Ugurayda9293352015-03-23 15:57:13 -07008454{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008455 struct mgmt_pending_cmd *cmd = data;
8456 struct mgmt_cp_remove_advertising *cp = cmd->param;
Arman Ugurayda9293352015-03-23 15:57:13 -07008457 struct mgmt_rp_remove_advertising rp;
8458
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008459 bt_dev_dbg(hdev, "err %d", err);
Arman Ugurayda9293352015-03-23 15:57:13 -07008460
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008461 memset(&rp, 0, sizeof(rp));
Florian Grandel01948332015-06-18 03:16:48 +02008462 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008463
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008464 if (err)
8465 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8466 mgmt_status(err));
8467 else
8468 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8469 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Arman Ugurayda9293352015-03-23 15:57:13 -07008470
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008471 mgmt_pending_free(cmd);
8472}
8473
8474static int remove_advertising_sync(struct hci_dev *hdev, void *data)
8475{
8476 struct mgmt_pending_cmd *cmd = data;
8477 struct mgmt_cp_remove_advertising *cp = cmd->param;
8478 int err;
8479
8480 err = hci_remove_advertising_sync(hdev, cmd->sk, cp->instance, true);
8481 if (err)
8482 return err;
8483
8484 if (list_empty(&hdev->adv_instances))
8485 err = hci_disable_advertising_sync(hdev);
8486
8487 return err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008488}
8489
8490static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
8491 void *data, u16 data_len)
8492{
8493 struct mgmt_cp_remove_advertising *cp = data;
Arman Ugurayda9293352015-03-23 15:57:13 -07008494 struct mgmt_pending_cmd *cmd;
Johan Hedberg952497b2015-06-18 21:05:31 +03008495 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008496
Marcel Holtmann181d6952020-05-06 09:57:47 +02008497 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07008498
Arman Ugurayda9293352015-03-23 15:57:13 -07008499 hci_dev_lock(hdev);
8500
Johan Hedberg952497b2015-06-18 21:05:31 +03008501 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02008502 err = mgmt_cmd_status(sk, hdev->id,
8503 MGMT_OP_REMOVE_ADVERTISING,
8504 MGMT_STATUS_INVALID_PARAMS);
8505 goto unlock;
8506 }
8507
Arman Ugurayda9293352015-03-23 15:57:13 -07008508 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
8509 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
8510 pending_find(MGMT_OP_SET_LE, hdev)) {
8511 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8512 MGMT_STATUS_BUSY);
8513 goto unlock;
8514 }
8515
Johan Hedberg17fd08f2015-11-26 12:15:59 +02008516 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07008517 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8518 MGMT_STATUS_INVALID_PARAMS);
8519 goto unlock;
8520 }
8521
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008522 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
Arman Ugurayda9293352015-03-23 15:57:13 -07008523 data_len);
8524 if (!cmd) {
8525 err = -ENOMEM;
8526 goto unlock;
8527 }
8528
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008529 err = hci_cmd_sync_queue(hdev, remove_advertising_sync, cmd,
8530 remove_advertising_complete);
Arman Ugurayda9293352015-03-23 15:57:13 -07008531 if (err < 0)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008532 mgmt_pending_free(cmd);
Arman Ugurayda9293352015-03-23 15:57:13 -07008533
8534unlock:
8535 hci_dev_unlock(hdev);
8536
8537 return err;
8538}
8539
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008540static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
8541 void *data, u16 data_len)
8542{
8543 struct mgmt_cp_get_adv_size_info *cp = data;
8544 struct mgmt_rp_get_adv_size_info rp;
8545 u32 flags, supported_flags;
8546 int err;
8547
Marcel Holtmann181d6952020-05-06 09:57:47 +02008548 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008549
8550 if (!lmp_le_capable(hdev))
8551 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8552 MGMT_STATUS_REJECTED);
8553
Daniel Winkler87597482020-08-25 16:31:50 -07008554 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008555 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8556 MGMT_STATUS_INVALID_PARAMS);
8557
8558 flags = __le32_to_cpu(cp->flags);
8559
8560 /* The current implementation only supports a subset of the specified
8561 * flags.
8562 */
8563 supported_flags = get_supported_adv_flags(hdev);
8564 if (flags & ~supported_flags)
8565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8566 MGMT_STATUS_INVALID_PARAMS);
8567
8568 rp.instance = cp->instance;
8569 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008570 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8571 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008572
8573 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8574 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8575
8576 return err;
8577}
8578
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008579static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008580 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008581 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008582 HCI_MGMT_NO_HDEV |
8583 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008584 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008585 HCI_MGMT_NO_HDEV |
8586 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008587 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008588 HCI_MGMT_NO_HDEV |
8589 HCI_MGMT_UNTRUSTED },
8590 { read_controller_info, MGMT_READ_INFO_SIZE,
8591 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008592 { set_powered, MGMT_SETTING_SIZE },
8593 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
8594 { set_connectable, MGMT_SETTING_SIZE },
8595 { set_fast_connectable, MGMT_SETTING_SIZE },
8596 { set_bondable, MGMT_SETTING_SIZE },
8597 { set_link_security, MGMT_SETTING_SIZE },
8598 { set_ssp, MGMT_SETTING_SIZE },
8599 { set_hs, MGMT_SETTING_SIZE },
8600 { set_le, MGMT_SETTING_SIZE },
8601 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
8602 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
8603 { add_uuid, MGMT_ADD_UUID_SIZE },
8604 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008605 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
8606 HCI_MGMT_VAR_LEN },
8607 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
8608 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008609 { disconnect, MGMT_DISCONNECT_SIZE },
8610 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
8611 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
8612 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
8613 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
8614 { pair_device, MGMT_PAIR_DEVICE_SIZE },
8615 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
8616 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
8617 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
8618 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
8619 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
8620 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008621 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
8622 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
8623 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008624 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
8625 { start_discovery, MGMT_START_DISCOVERY_SIZE },
8626 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
8627 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
8628 { block_device, MGMT_BLOCK_DEVICE_SIZE },
8629 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
8630 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
8631 { set_advertising, MGMT_SETTING_SIZE },
8632 { set_bredr, MGMT_SETTING_SIZE },
8633 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
8634 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
8635 { set_secure_conn, MGMT_SETTING_SIZE },
8636 { set_debug_keys, MGMT_SETTING_SIZE },
8637 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008638 { load_irks, MGMT_LOAD_IRKS_SIZE,
8639 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008640 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
8641 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
8642 { add_device, MGMT_ADD_DEVICE_SIZE },
8643 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008644 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
8645 HCI_MGMT_VAR_LEN },
8646 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008647 HCI_MGMT_NO_HDEV |
8648 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008649 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008650 HCI_MGMT_UNCONFIGURED |
8651 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008652 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
8653 HCI_MGMT_UNCONFIGURED },
8654 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
8655 HCI_MGMT_UNCONFIGURED },
8656 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
8657 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07008658 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07008659 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008660 HCI_MGMT_NO_HDEV |
8661 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07008662 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07008663 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
8664 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07008665 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008666 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02008667 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008668 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
8669 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02008670 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05308671 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05308672 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00008673 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
8674 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00008675 { set_wideband_speech, MGMT_SETTING_SIZE },
Daniel Winkler4d9b9522020-12-03 12:12:52 -08008676 { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02008677 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02008678 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
8679 HCI_MGMT_UNTRUSTED |
8680 HCI_MGMT_HDEV_OPTIONAL },
8681 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
8682 HCI_MGMT_VAR_LEN |
8683 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00008684 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
8685 HCI_MGMT_UNTRUSTED },
8686 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
8687 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02008688 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
8689 HCI_MGMT_UNTRUSTED },
8690 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
8691 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02008692 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
8693 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02008694 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02008695 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
8696 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02008697 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Daniel Winkler12410572020-12-03 12:12:49 -08008698 { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE,
8699 HCI_MGMT_VAR_LEN },
8700 { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
8701 HCI_MGMT_VAR_LEN },
Archie Pusakab4a221e2021-01-22 16:36:11 +08008702 { add_adv_patterns_monitor_rssi,
8703 MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
8704 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008705};
8706
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008707void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008708{
Marcel Holtmannced85542015-03-14 19:27:56 -07008709 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03008710
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008711 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8712 return;
8713
Marcel Holtmannf9207332015-03-14 19:27:55 -07008714 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008715 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008716 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8717 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
8718 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008719 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008720 } else {
8721 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
8722 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008723 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008724 }
8725 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008726 case HCI_AMP:
8727 ev.type = 0x02;
8728 break;
8729 default:
8730 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008731 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008732
8733 ev.bus = hdev->bus;
8734
8735 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
8736 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008737}
8738
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008739void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008740{
Marcel Holtmannced85542015-03-14 19:27:56 -07008741 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02008742 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02008743
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008744 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8745 return;
8746
Marcel Holtmannf9207332015-03-14 19:27:55 -07008747 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008748 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008749 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02008750
Marcel Holtmannf9207332015-03-14 19:27:55 -07008751 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8752 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
8753 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008754 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008755 } else {
8756 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
8757 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008758 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008759 }
8760 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008761 case HCI_AMP:
8762 ev.type = 0x02;
8763 break;
8764 default:
8765 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008766 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008767
8768 ev.bus = hdev->bus;
8769
8770 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
8771 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008772}
8773
Johan Hedberg2ff13892015-11-25 16:15:44 +02008774void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05008775{
8776 struct cmd_lookup match = { NULL, hdev };
8777
Marcel Holtmann181d6952020-05-06 09:57:47 +02008778 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05008779
Johan Hedberg2ff13892015-11-25 16:15:44 +02008780 hci_dev_lock(hdev);
8781
8782 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008783 restart_le_actions(hdev);
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07008784 hci_update_passive_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08008785 }
8786
Johan Hedberg229ab392013-03-15 17:06:53 -05008787 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
8788
8789 new_settings(hdev, match.sk);
8790
Johan Hedberg229ab392013-03-15 17:06:53 -05008791 if (match.sk)
8792 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02008793
8794 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05008795}
8796
Johan Hedberg2ff13892015-11-25 16:15:44 +02008797void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02008798{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02008799 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02008800 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02008801
Johan Hedberg229ab392013-03-15 17:06:53 -05008802 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02008803
8804 /* If the power off is because of hdev unregistration let
8805 * use the appropriate INVALID_INDEX status. Otherwise use
8806 * NOT_POWERED. We cover both scenarios here since later in
8807 * mgmt_index_removed() any hci_conn callbacks will have already
8808 * been triggered, potentially causing misleading DISCONNECTED
8809 * status responses.
8810 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008811 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02008812 status = MGMT_STATUS_INVALID_INDEX;
8813 else
8814 status = MGMT_STATUS_NOT_POWERED;
8815
8816 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008817
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008818 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008819 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8820 zero_cod, sizeof(zero_cod),
8821 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008822 ext_info_changed(hdev, NULL);
8823 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008824
Johan Hedberg2ff13892015-11-25 16:15:44 +02008825 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008826
8827 if (match.sk)
8828 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008829}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008830
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008831void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008832{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008833 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008834 u8 status;
8835
Johan Hedberg333ae952015-03-17 13:48:47 +02008836 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008837 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008838 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008839
8840 if (err == -ERFKILL)
8841 status = MGMT_STATUS_RFKILLED;
8842 else
8843 status = MGMT_STATUS_FAILED;
8844
Johan Hedberga69e8372015-03-06 21:08:53 +02008845 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008846
8847 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008848}
8849
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008850void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8851 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008852{
Johan Hedberg86742e12011-11-07 23:13:38 +02008853 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008854
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008855 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008856
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008857 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008858 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008859 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008860 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008861 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008862 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008863
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008864 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008865}
Johan Hedbergf7520542011-01-20 12:34:39 +02008866
Johan Hedbergd7b25452014-05-23 13:19:53 +03008867static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8868{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008869 switch (ltk->type) {
8870 case SMP_LTK:
Archie Pusakafad646e2021-05-31 16:37:25 +08008871 case SMP_LTK_RESPONDER:
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008872 if (ltk->authenticated)
8873 return MGMT_LTK_AUTHENTICATED;
8874 return MGMT_LTK_UNAUTHENTICATED;
8875 case SMP_LTK_P256:
8876 if (ltk->authenticated)
8877 return MGMT_LTK_P256_AUTH;
8878 return MGMT_LTK_P256_UNAUTH;
8879 case SMP_LTK_P256_DEBUG:
8880 return MGMT_LTK_P256_DEBUG;
8881 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008882
8883 return MGMT_LTK_UNAUTHENTICATED;
8884}
8885
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008886void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008887{
8888 struct mgmt_ev_new_long_term_key ev;
8889
8890 memset(&ev, 0, sizeof(ev));
8891
Marcel Holtmann5192d302014-02-19 17:11:58 -08008892 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008893 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008894 * to store long term keys. Their addresses will change the
8895 * next time around.
8896 *
8897 * Only when a remote device provides an identity address
8898 * make sure the long term key is stored. If the remote
8899 * identity is known, the long term keys are internally
8900 * mapped to the identity address. So allow static random
8901 * and public addresses here.
8902 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008903 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8904 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8905 ev.store_hint = 0x00;
8906 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008907 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008908
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008909 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008910 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008911 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008912 ev.key.enc_size = key->enc_size;
8913 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008914 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008915
Johan Hedberg2ceba532014-06-16 19:25:16 +03008916 if (key->type == SMP_LTK)
Archie Pusakafad646e2021-05-31 16:37:25 +08008917 ev.key.initiator = 1;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008918
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008919 /* Make sure we copy only the significant bytes based on the
8920 * encryption key size, and set the rest of the value to zeroes.
8921 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008922 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008923 memset(ev.key.val + key->enc_size, 0,
8924 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008925
Marcel Holtmann083368f2013-10-15 14:26:29 -07008926 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008927}
8928
Johan Hedbergcad20c22015-10-12 13:36:19 +02008929void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008930{
8931 struct mgmt_ev_new_irk ev;
8932
8933 memset(&ev, 0, sizeof(ev));
8934
Johan Hedbergcad20c22015-10-12 13:36:19 +02008935 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008936
Johan Hedberg95fbac82014-02-19 15:18:31 +02008937 bacpy(&ev.rpa, &irk->rpa);
8938 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8939 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8940 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8941
8942 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8943}
8944
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008945void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8946 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008947{
8948 struct mgmt_ev_new_csrk ev;
8949
8950 memset(&ev, 0, sizeof(ev));
8951
8952 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008953 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008954 * to store signature resolving keys. Their addresses will change
8955 * the next time around.
8956 *
8957 * Only when a remote device provides an identity address
8958 * make sure the signature resolving key is stored. So allow
8959 * static random and public addresses here.
8960 */
8961 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8962 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8963 ev.store_hint = 0x00;
8964 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008965 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008966
8967 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8968 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008969 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008970 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8971
8972 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8973}
8974
Andre Guedesffb5a8272014-07-01 18:10:11 -03008975void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008976 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8977 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008978{
8979 struct mgmt_ev_new_conn_param ev;
8980
Johan Hedbergc103aea2014-07-02 17:37:34 +03008981 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8982 return;
8983
Andre Guedesffb5a8272014-07-01 18:10:11 -03008984 memset(&ev, 0, sizeof(ev));
8985 bacpy(&ev.addr.bdaddr, bdaddr);
8986 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008987 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008988 ev.min_interval = cpu_to_le16(min_interval);
8989 ev.max_interval = cpu_to_le16(max_interval);
8990 ev.latency = cpu_to_le16(latency);
8991 ev.timeout = cpu_to_le16(timeout);
8992
8993 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8994}
8995
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008996void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
Yu Liu1c6ed312021-04-09 15:04:06 -07008997 u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008998{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008999 char buf[512];
9000 struct mgmt_ev_device_connected *ev = (void *) buf;
9001 u16 eir_len = 0;
Yu Liu1c6ed312021-04-09 15:04:06 -07009002 u32 flags = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02009003
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00009004 bacpy(&ev->addr.bdaddr, &conn->dst);
9005 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02009006
Yu Liu1c6ed312021-04-09 15:04:06 -07009007 if (conn->out)
9008 flags |= MGMT_DEV_FOUND_INITIATED_CONN;
9009
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02009010 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02009011
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009012 /* We must ensure that the EIR Data fields are ordered and
9013 * unique. Keep it simple for now and avoid the problem by not
9014 * adding any BR/EDR data to the LE adv.
9015 */
9016 if (conn->le_adv_data_len > 0) {
9017 memcpy(&ev->eir[eir_len],
9018 conn->le_adv_data, conn->le_adv_data_len);
9019 eir_len = conn->le_adv_data_len;
9020 } else {
9021 if (name_len > 0)
9022 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
9023 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009024
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00009025 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009026 eir_len = eir_append_data(ev->eir, eir_len,
9027 EIR_CLASS_OF_DEV,
9028 conn->dev_class, 3);
9029 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02009030
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009031 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009032
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07009033 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
9034 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02009035}
9036
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009037static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009038{
Johan Hedberg8962ee72011-01-20 12:40:27 +02009039 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009040
Johan Hedbergf5818c22014-12-05 13:36:02 +02009041 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009042
9043 *sk = cmd->sk;
9044 sock_hold(*sk);
9045
Johan Hedberga664b5b2011-02-19 12:06:02 -03009046 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009047}
9048
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009049static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02009050{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009051 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02009052 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02009053
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009054 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
9055
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02009056 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02009057 mgmt_pending_remove(cmd);
9058}
9059
Johan Hedberg84c61d92014-08-01 11:13:30 +03009060bool mgmt_powering_down(struct hci_dev *hdev)
9061{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009062 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03009063 struct mgmt_mode *cp;
9064
Johan Hedberg333ae952015-03-17 13:48:47 +02009065 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03009066 if (!cmd)
9067 return false;
9068
9069 cp = cmd->param;
9070 if (!cp->val)
9071 return true;
9072
9073 return false;
9074}
9075
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009076void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009077 u8 link_type, u8 addr_type, u8 reason,
9078 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02009079{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009080 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009081 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009082
Johan Hedberg84c61d92014-08-01 11:13:30 +03009083 /* The connection is still in hci_conn_hash so test for 1
9084 * instead of 0 to know if this is the last one.
9085 */
9086 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9087 cancel_delayed_work(&hdev->power_off);
9088 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02009089 }
9090
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009091 if (!mgmt_connected)
9092 return;
9093
Andre Guedes57eb7762013-10-30 19:01:41 -03009094 if (link_type != ACL_LINK && link_type != LE_LINK)
9095 return;
9096
Johan Hedberg744cf192011-11-08 20:40:14 +02009097 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02009098
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009099 bacpy(&ev.addr.bdaddr, bdaddr);
9100 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9101 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02009102
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07009103 /* Report disconnects due to suspend */
9104 if (hdev->suspended)
9105 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
9106
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009107 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009108
9109 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01009110 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009111
Johan Hedberg124f6e32012-02-09 13:50:12 +02009112 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009113 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009114}
9115
Marcel Holtmann78929242013-10-06 23:55:47 -07009116void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
9117 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009118{
Andre Guedes3655bba2013-10-30 19:01:40 -03009119 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
9120 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009121 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009122
Jefferson Delfes36a75f12012-09-18 13:36:54 -04009123 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
9124 hdev);
9125
Johan Hedberg333ae952015-03-17 13:48:47 +02009126 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009127 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07009128 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009129
Andre Guedes3655bba2013-10-30 19:01:40 -03009130 cp = cmd->param;
9131
9132 if (bacmp(bdaddr, &cp->addr.bdaddr))
9133 return;
9134
9135 if (cp->addr.type != bdaddr_type)
9136 return;
9137
Johan Hedbergf5818c22014-12-05 13:36:02 +02009138 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009139 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02009140}
Johan Hedberg17d5c042011-01-22 06:09:08 +02009141
Marcel Holtmann445608d2013-10-06 23:55:48 -07009142void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9143 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02009144{
9145 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02009146
Johan Hedberg84c61d92014-08-01 11:13:30 +03009147 /* The connection is still in hci_conn_hash so test for 1
9148 * instead of 0 to know if this is the last one.
9149 */
9150 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9151 cancel_delayed_work(&hdev->power_off);
9152 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02009153 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02009154
Johan Hedberg4c659c32011-11-07 23:13:39 +02009155 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009156 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02009157 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009158
Marcel Holtmann445608d2013-10-06 23:55:48 -07009159 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009160}
Johan Hedberg980e1a52011-01-22 06:10:07 +02009161
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009162void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009163{
9164 struct mgmt_ev_pin_code_request ev;
9165
Johan Hedbergd8457692012-02-17 14:24:57 +02009166 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03009167 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02009168 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009169
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009170 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009171}
9172
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009173void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9174 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009175{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009176 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009177
Johan Hedberg333ae952015-03-17 13:48:47 +02009178 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009179 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009180 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009181
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009182 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009183 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009184}
9185
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009186void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9187 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009188{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009189 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009190
Johan Hedberg333ae952015-03-17 13:48:47 +02009191 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009192 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009193 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009194
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009195 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009196 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009197}
Johan Hedberga5c29682011-02-19 12:05:57 -03009198
Johan Hedberg744cf192011-11-08 20:40:14 +02009199int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02009200 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009201 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03009202{
9203 struct mgmt_ev_user_confirm_request ev;
9204
Marcel Holtmann181d6952020-05-06 09:57:47 +02009205 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03009206
Johan Hedberg272d90d2012-02-09 15:26:12 +02009207 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009208 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07009209 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02009210 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03009211
Johan Hedberg744cf192011-11-08 20:40:14 +02009212 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009213 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03009214}
9215
Johan Hedberg272d90d2012-02-09 15:26:12 +02009216int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009217 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08009218{
9219 struct mgmt_ev_user_passkey_request ev;
9220
Marcel Holtmann181d6952020-05-06 09:57:47 +02009221 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08009222
Johan Hedberg272d90d2012-02-09 15:26:12 +02009223 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009224 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08009225
9226 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009227 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08009228}
9229
Brian Gix0df4c182011-11-16 13:53:13 -08009230static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009231 u8 link_type, u8 addr_type, u8 status,
9232 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03009233{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009234 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03009235
Johan Hedberg333ae952015-03-17 13:48:47 +02009236 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03009237 if (!cmd)
9238 return -ENOENT;
9239
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009240 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009241 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03009242
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009243 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03009244}
9245
Johan Hedberg744cf192011-11-08 20:40:14 +02009246int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009247 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009248{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009249 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009250 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009251}
9252
Johan Hedberg272d90d2012-02-09 15:26:12 +02009253int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009254 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009255{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009256 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009257 status,
9258 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009259}
Johan Hedberg2a611692011-02-19 12:06:00 -03009260
Brian Gix604086b2011-11-23 08:28:33 -08009261int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009262 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009263{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009264 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009265 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009266}
9267
Johan Hedberg272d90d2012-02-09 15:26:12 +02009268int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009269 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009270{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009271 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009272 status,
9273 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009274}
9275
Johan Hedberg92a25252012-09-06 18:39:26 +03009276int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
9277 u8 link_type, u8 addr_type, u32 passkey,
9278 u8 entered)
9279{
9280 struct mgmt_ev_passkey_notify ev;
9281
Marcel Holtmann181d6952020-05-06 09:57:47 +02009282 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03009283
9284 bacpy(&ev.addr.bdaddr, bdaddr);
9285 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9286 ev.passkey = __cpu_to_le32(passkey);
9287 ev.entered = entered;
9288
9289 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
9290}
9291
Johan Hedberge1e930f2014-09-08 17:09:49 -07009292void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03009293{
9294 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009295 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07009296 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03009297
Johan Hedberge1e930f2014-09-08 17:09:49 -07009298 bacpy(&ev.addr.bdaddr, &conn->dst);
9299 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
9300 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03009301
Johan Hedberge1e930f2014-09-08 17:09:49 -07009302 cmd = find_pairing(conn);
9303
9304 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
9305 cmd ? cmd->sk : NULL);
9306
Johan Hedberga511b352014-12-11 21:45:45 +02009307 if (cmd) {
9308 cmd->cmd_complete(cmd, status);
9309 mgmt_pending_remove(cmd);
9310 }
Johan Hedberg2a611692011-02-19 12:06:00 -03009311}
Johan Hedbergb312b1612011-03-16 14:29:37 +02009312
Marcel Holtmann464996a2013-10-15 14:26:24 -07009313void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009314{
9315 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07009316 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009317
9318 if (status) {
9319 u8 mgmt_err = mgmt_status(status);
9320 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009321 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009322 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009323 }
9324
Marcel Holtmann464996a2013-10-15 14:26:24 -07009325 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07009326 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009327 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009328 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02009329
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009330 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009331 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009332
Johan Hedberg47990ea2012-02-22 11:58:37 +02009333 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07009334 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009335
9336 if (match.sk)
9337 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009338}
9339
Johan Hedberg890ea892013-03-15 17:06:52 -05009340static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02009341{
Johan Hedberg890ea892013-03-15 17:06:52 -05009342 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009343 struct hci_cp_write_eir cp;
9344
Johan Hedberg976eb202012-10-24 21:12:01 +03009345 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05009346 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009347
Johan Hedbergc80da272012-02-22 15:38:48 +02009348 memset(hdev->eir, 0, sizeof(hdev->eir));
9349
Johan Hedbergcacaf522012-02-21 00:52:42 +02009350 memset(&cp, 0, sizeof(cp));
9351
Johan Hedberg890ea892013-03-15 17:06:52 -05009352 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02009353}
9354
Marcel Holtmann3e248562013-10-15 14:26:25 -07009355void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009356{
9357 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05009358 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009359 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009360
9361 if (status) {
9362 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009363
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009364 if (enable && hci_dev_test_and_clear_flag(hdev,
9365 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009366 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009367 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009368 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009369
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009370 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
9371 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009372 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009373 }
9374
9375 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07009376 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009377 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009378 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009379 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009380 changed = hci_dev_test_and_clear_flag(hdev,
9381 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009382 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009383 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009384 }
9385
9386 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
9387
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009388 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07009389 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009390
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02009391 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009392 sock_put(match.sk);
9393
Johan Hedberg890ea892013-03-15 17:06:52 -05009394 hci_req_init(&req, hdev);
9395
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009396 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
9397 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03009398 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
9399 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02009400 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009401 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05009402 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009403 }
Johan Hedberg890ea892013-03-15 17:06:52 -05009404
9405 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009406}
9407
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009408static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02009409{
9410 struct cmd_lookup *match = data;
9411
Johan Hedberg90e70452012-02-23 23:09:40 +02009412 if (match->sk == NULL) {
9413 match->sk = cmd->sk;
9414 sock_hold(match->sk);
9415 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009416}
9417
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07009418void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
9419 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009420{
Johan Hedberg90e70452012-02-23 23:09:40 +02009421 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009422
Johan Hedberg92da6092013-03-15 17:06:55 -05009423 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
9424 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
9425 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02009426
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009427 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009428 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
9429 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009430 ext_info_changed(hdev, NULL);
9431 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009432
9433 if (match.sk)
9434 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009435}
9436
Marcel Holtmann7667da32013-10-15 14:26:27 -07009437void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02009438{
Johan Hedbergb312b1612011-03-16 14:29:37 +02009439 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009440 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009441
Johan Hedberg13928972013-03-15 17:07:00 -05009442 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07009443 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009444
9445 memset(&ev, 0, sizeof(ev));
9446 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009447 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009448
Johan Hedberg333ae952015-03-17 13:48:47 +02009449 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05009450 if (!cmd) {
9451 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02009452
Johan Hedberg13928972013-03-15 17:07:00 -05009453 /* If this is a HCI command related to powering on the
9454 * HCI dev don't send any mgmt signals.
9455 */
Johan Hedberg333ae952015-03-17 13:48:47 +02009456 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07009457 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009458 }
9459
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009460 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
9461 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009462 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009463}
Szymon Jancc35938b2011-03-22 13:12:21 +01009464
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009465static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
9466{
9467 int i;
9468
9469 for (i = 0; i < uuid_count; i++) {
9470 if (!memcmp(uuid, uuids[i], 16))
9471 return true;
9472 }
9473
9474 return false;
9475}
9476
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009477static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
9478{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009479 u16 parsed = 0;
9480
9481 while (parsed < eir_len) {
9482 u8 field_len = eir[0];
9483 u8 uuid[16];
9484 int i;
9485
9486 if (field_len == 0)
9487 break;
9488
9489 if (eir_len - parsed < field_len + 1)
9490 break;
9491
9492 switch (eir[1]) {
9493 case EIR_UUID16_ALL:
9494 case EIR_UUID16_SOME:
9495 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009496 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009497 uuid[13] = eir[i + 3];
9498 uuid[12] = eir[i + 2];
9499 if (has_uuid(uuid, uuid_count, uuids))
9500 return true;
9501 }
9502 break;
9503 case EIR_UUID32_ALL:
9504 case EIR_UUID32_SOME:
9505 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009506 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009507 uuid[15] = eir[i + 5];
9508 uuid[14] = eir[i + 4];
9509 uuid[13] = eir[i + 3];
9510 uuid[12] = eir[i + 2];
9511 if (has_uuid(uuid, uuid_count, uuids))
9512 return true;
9513 }
9514 break;
9515 case EIR_UUID128_ALL:
9516 case EIR_UUID128_SOME:
9517 for (i = 0; i + 17 <= field_len; i += 16) {
9518 memcpy(uuid, eir + i + 2, 16);
9519 if (has_uuid(uuid, uuid_count, uuids))
9520 return true;
9521 }
9522 break;
9523 }
9524
9525 parsed += field_len + 1;
9526 eir += field_len + 1;
9527 }
9528
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009529 return false;
9530}
9531
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009532static void restart_le_scan(struct hci_dev *hdev)
9533{
9534 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009535 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009536 return;
9537
9538 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
9539 hdev->discovery.scan_start +
9540 hdev->discovery.scan_duration))
9541 return;
9542
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02009543 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009544 DISCOV_LE_RESTART_DELAY);
9545}
9546
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009547static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
9548 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
9549{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009550 /* If a RSSI threshold has been specified, and
9551 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
9552 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
9553 * is set, let it through for further processing, as we might need to
9554 * restart the scan.
9555 *
9556 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
9557 * the results are also dropped.
9558 */
9559 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9560 (rssi == HCI_RSSI_INVALID ||
9561 (rssi < hdev->discovery.rssi &&
9562 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
9563 return false;
9564
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009565 if (hdev->discovery.uuid_count != 0) {
9566 /* If a list of UUIDs is provided in filter, results with no
9567 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009568 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009569 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
9570 hdev->discovery.uuids) &&
9571 !eir_has_uuids(scan_rsp, scan_rsp_len,
9572 hdev->discovery.uuid_count,
9573 hdev->discovery.uuids))
9574 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009575 }
9576
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009577 /* If duplicate filtering does not report RSSI changes, then restart
9578 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009579 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009580 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
9581 restart_le_scan(hdev);
9582
9583 /* Validate RSSI value against the RSSI threshold once more. */
9584 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9585 rssi < hdev->discovery.rssi)
9586 return false;
9587 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009588
9589 return true;
9590}
9591
Marcel Holtmann901801b2013-10-06 23:55:51 -07009592void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02009593 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
9594 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03009595{
Johan Hedberge319d2e2012-01-15 19:51:59 +02009596 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009597 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02009598 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03009599
Johan Hedberg75ce2082014-07-02 22:42:01 +03009600 /* Don't send events for a non-kernel initiated discovery. With
9601 * LE one exception is if we have pend_le_reports > 0 in which
9602 * case we're doing passive scanning and want these events.
9603 */
9604 if (!hci_discovery_active(hdev)) {
9605 if (link_type == ACL_LINK)
9606 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009607 if (link_type == LE_LINK &&
9608 list_empty(&hdev->pend_le_reports) &&
9609 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03009610 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009611 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03009612 }
Andre Guedes12602d02013-04-30 15:29:40 -03009613
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08009614 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009615 /* We are using service discovery */
9616 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
9617 scan_rsp_len))
9618 return;
9619 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01009620
Johan Hedberg78b781c2016-01-05 13:19:32 +02009621 if (hdev->discovery.limited) {
9622 /* Check for limited discoverable bit */
9623 if (dev_class) {
9624 if (!(dev_class[1] & 0x20))
9625 return;
9626 } else {
9627 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
9628 if (!flags || !(flags[0] & LE_AD_LIMITED))
9629 return;
9630 }
9631 }
9632
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009633 /* Make sure that the buffer is big enough. The 5 extra bytes
9634 * are for the potential CoD field.
9635 */
9636 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07009637 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03009638
Johan Hedberg1dc06092012-01-15 21:01:23 +02009639 memset(buf, 0, sizeof(buf));
9640
Marcel Holtmannda25cf62014-12-05 13:03:35 +01009641 /* In case of device discovery with BR/EDR devices (pre 1.2), the
9642 * RSSI value was reported as 0 when not available. This behavior
9643 * is kept when using device discovery. This is required for full
9644 * backwards compatibility with the API.
9645 *
9646 * However when using service discovery, the value 127 will be
9647 * returned when the RSSI is not available.
9648 */
Szymon Janc91200e92015-01-22 16:57:05 +01009649 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
9650 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01009651 rssi = 0;
9652
Johan Hedberg841c5642014-07-07 12:45:54 +03009653 bacpy(&ev->addr.bdaddr, bdaddr);
9654 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02009655 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02009656 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03009657
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009658 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009659 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02009660 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03009661
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02009662 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
9663 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02009664 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009665 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02009666
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009667 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009668 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009669 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009670
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009671 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
9672 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03009673
Marcel Holtmann901801b2013-10-06 23:55:51 -07009674 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03009675}
Johan Hedberga88a9652011-03-30 13:18:12 +03009676
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009677void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9678 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03009679{
Johan Hedbergb644ba32012-01-17 21:48:47 +02009680 struct mgmt_ev_device_found *ev;
9681 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
9682 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03009683
Johan Hedbergb644ba32012-01-17 21:48:47 +02009684 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03009685
Johan Hedbergb644ba32012-01-17 21:48:47 +02009686 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03009687
Johan Hedbergb644ba32012-01-17 21:48:47 +02009688 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009689 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009690 ev->rssi = rssi;
9691
9692 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009693 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009694
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009695 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009696
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009697 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03009698}
Johan Hedberg314b2382011-04-27 10:29:57 -04009699
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009700void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04009701{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009702 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02009703
Marcel Holtmann181d6952020-05-06 09:57:47 +02009704 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03009705
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009706 memset(&ev, 0, sizeof(ev));
9707 ev.type = hdev->discovery.type;
9708 ev.discovering = discovering;
9709
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009710 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04009711}
Antti Julku5e762442011-08-25 16:48:02 +03009712
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07009713void mgmt_suspending(struct hci_dev *hdev, u8 state)
9714{
9715 struct mgmt_ev_controller_suspend ev;
9716
9717 ev.suspend_state = state;
9718 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
9719}
9720
9721void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
9722 u8 addr_type)
9723{
9724 struct mgmt_ev_controller_resume ev;
9725
9726 ev.wake_reason = reason;
9727 if (bdaddr) {
9728 bacpy(&ev.addr.bdaddr, bdaddr);
9729 ev.addr.type = addr_type;
9730 } else {
9731 memset(&ev.addr, 0, sizeof(ev.addr));
9732 }
9733
9734 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
9735}
9736
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009737static struct hci_mgmt_chan chan = {
9738 .channel = HCI_CHANNEL_CONTROL,
9739 .handler_count = ARRAY_SIZE(mgmt_handlers),
9740 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02009741 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009742};
9743
9744int mgmt_init(void)
9745{
9746 return hci_mgmt_chan_register(&chan);
9747}
9748
9749void mgmt_exit(void)
9750{
9751 hci_mgmt_chan_unregister(&chan);
9752}