blob: 2697e1ef19647ac25c2c2eacef0502266e93aa76 [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"
Joseph Hwang258f56d2021-11-02 15:19:29 +080042#include "aosp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020043
Johan Hedberg2da9c552012-02-17 14:39:28 +020044#define MGMT_VERSION 1
Marcel Holtmann43e59cb2021-06-15 21:23:35 +020045#define MGMT_REVISION 21
Johan Hedberg02d98122010-12-13 21:07:04 +020046
Johan Hedberge70bb2e2012-02-13 16:59:33 +020047static const u16 mgmt_commands[] = {
48 MGMT_OP_READ_INDEX_LIST,
49 MGMT_OP_READ_INFO,
50 MGMT_OP_SET_POWERED,
51 MGMT_OP_SET_DISCOVERABLE,
52 MGMT_OP_SET_CONNECTABLE,
53 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030054 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020055 MGMT_OP_SET_LINK_SECURITY,
56 MGMT_OP_SET_SSP,
57 MGMT_OP_SET_HS,
58 MGMT_OP_SET_LE,
59 MGMT_OP_SET_DEV_CLASS,
60 MGMT_OP_SET_LOCAL_NAME,
61 MGMT_OP_ADD_UUID,
62 MGMT_OP_REMOVE_UUID,
63 MGMT_OP_LOAD_LINK_KEYS,
64 MGMT_OP_LOAD_LONG_TERM_KEYS,
65 MGMT_OP_DISCONNECT,
66 MGMT_OP_GET_CONNECTIONS,
67 MGMT_OP_PIN_CODE_REPLY,
68 MGMT_OP_PIN_CODE_NEG_REPLY,
69 MGMT_OP_SET_IO_CAPABILITY,
70 MGMT_OP_PAIR_DEVICE,
71 MGMT_OP_CANCEL_PAIR_DEVICE,
72 MGMT_OP_UNPAIR_DEVICE,
73 MGMT_OP_USER_CONFIRM_REPLY,
74 MGMT_OP_USER_CONFIRM_NEG_REPLY,
75 MGMT_OP_USER_PASSKEY_REPLY,
76 MGMT_OP_USER_PASSKEY_NEG_REPLY,
77 MGMT_OP_READ_LOCAL_OOB_DATA,
78 MGMT_OP_ADD_REMOTE_OOB_DATA,
79 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
80 MGMT_OP_START_DISCOVERY,
81 MGMT_OP_STOP_DISCOVERY,
82 MGMT_OP_CONFIRM_NAME,
83 MGMT_OP_BLOCK_DEVICE,
84 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070085 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030086 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030087 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070088 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070089 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080090 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080091 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020092 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020093 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020094 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030095 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020096 MGMT_OP_ADD_DEVICE,
97 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030098 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020099 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200100 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +0200101 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200102 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100103 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700104 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700105 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700106 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700107 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700108 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100109 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200110 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200111 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200112 MGMT_OP_SET_APPEARANCE,
Marcel Holtmann02431b62021-03-24 15:10:55 +0100113 MGMT_OP_GET_PHY_CONFIGURATION,
114 MGMT_OP_SET_PHY_CONFIGURATION,
Alain Michaud600a8742020-01-07 00:43:17 +0000115 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000116 MGMT_OP_SET_WIDEBAND_SPEECH,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800117 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200118 MGMT_OP_READ_EXP_FEATURES_INFO,
119 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000120 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
121 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200122 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
123 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200124 MGMT_OP_GET_DEVICE_FLAGS,
125 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200126 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200127 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200128 MGMT_OP_REMOVE_ADV_MONITOR,
Daniel Winkler12410572020-12-03 12:12:49 -0800129 MGMT_OP_ADD_EXT_ADV_PARAMS,
130 MGMT_OP_ADD_EXT_ADV_DATA,
Archie Pusakab4a221e2021-01-22 16:36:11 +0800131 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200132};
133
134static const u16 mgmt_events[] = {
135 MGMT_EV_CONTROLLER_ERROR,
136 MGMT_EV_INDEX_ADDED,
137 MGMT_EV_INDEX_REMOVED,
138 MGMT_EV_NEW_SETTINGS,
139 MGMT_EV_CLASS_OF_DEV_CHANGED,
140 MGMT_EV_LOCAL_NAME_CHANGED,
141 MGMT_EV_NEW_LINK_KEY,
142 MGMT_EV_NEW_LONG_TERM_KEY,
143 MGMT_EV_DEVICE_CONNECTED,
144 MGMT_EV_DEVICE_DISCONNECTED,
145 MGMT_EV_CONNECT_FAILED,
146 MGMT_EV_PIN_CODE_REQUEST,
147 MGMT_EV_USER_CONFIRM_REQUEST,
148 MGMT_EV_USER_PASSKEY_REQUEST,
149 MGMT_EV_AUTH_FAILED,
150 MGMT_EV_DEVICE_FOUND,
151 MGMT_EV_DISCOVERING,
152 MGMT_EV_DEVICE_BLOCKED,
153 MGMT_EV_DEVICE_UNBLOCKED,
154 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300155 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800156 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700157 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200158 MGMT_EV_DEVICE_ADDED,
159 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300160 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200161 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200162 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200163 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700164 MGMT_EV_EXT_INDEX_ADDED,
165 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700166 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700167 MGMT_EV_ADVERTISING_ADDED,
168 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200169 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200170 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200171 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200172 MGMT_EV_DEVICE_FLAGS_CHANGED,
Marcel Holtmann3d34a712021-03-24 15:10:56 +0100173 MGMT_EV_ADV_MONITOR_ADDED,
174 MGMT_EV_ADV_MONITOR_REMOVED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700175 MGMT_EV_CONTROLLER_SUSPEND,
176 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200177};
178
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700179static const u16 mgmt_untrusted_commands[] = {
180 MGMT_OP_READ_INDEX_LIST,
181 MGMT_OP_READ_INFO,
182 MGMT_OP_READ_UNCONF_INDEX_LIST,
183 MGMT_OP_READ_CONFIG_INFO,
184 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200185 MGMT_OP_READ_EXT_INFO,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800186 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200187 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000188 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200189 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700190};
191
192static const u16 mgmt_untrusted_events[] = {
193 MGMT_EV_INDEX_ADDED,
194 MGMT_EV_INDEX_REMOVED,
195 MGMT_EV_NEW_SETTINGS,
196 MGMT_EV_CLASS_OF_DEV_CHANGED,
197 MGMT_EV_LOCAL_NAME_CHANGED,
198 MGMT_EV_UNCONF_INDEX_ADDED,
199 MGMT_EV_UNCONF_INDEX_REMOVED,
200 MGMT_EV_NEW_CONFIG_OPTIONS,
201 MGMT_EV_EXT_INDEX_ADDED,
202 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200203 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200204 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700205};
206
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800207#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200208
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200209#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
210 "\x00\x00\x00\x00\x00\x00\x00\x00"
211
Johan Hedbergca69b792011-11-11 18:10:00 +0200212/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000213static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200214 MGMT_STATUS_SUCCESS,
215 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
216 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
217 MGMT_STATUS_FAILED, /* Hardware Failure */
218 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
219 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200220 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200221 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
222 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
223 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
224 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
225 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
226 MGMT_STATUS_BUSY, /* Command Disallowed */
227 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
228 MGMT_STATUS_REJECTED, /* Rejected Security */
229 MGMT_STATUS_REJECTED, /* Rejected Personal */
230 MGMT_STATUS_TIMEOUT, /* Host Timeout */
231 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
232 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
233 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
234 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
235 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
236 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
237 MGMT_STATUS_BUSY, /* Repeated Attempts */
238 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
239 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
240 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
241 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
242 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
243 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
244 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
245 MGMT_STATUS_FAILED, /* Unspecified Error */
246 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
247 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
248 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
249 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
250 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
251 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
252 MGMT_STATUS_FAILED, /* Unit Link Key Used */
253 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
254 MGMT_STATUS_TIMEOUT, /* Instant Passed */
255 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
256 MGMT_STATUS_FAILED, /* Transaction Collision */
Yu Liu4ef36a52021-04-19 16:53:30 -0700257 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200258 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
259 MGMT_STATUS_REJECTED, /* QoS Rejected */
260 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
261 MGMT_STATUS_REJECTED, /* Insufficient Security */
262 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
Yu Liu4ef36a52021-04-19 16:53:30 -0700263 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200264 MGMT_STATUS_BUSY, /* Role Switch Pending */
Yu Liu4ef36a52021-04-19 16:53:30 -0700265 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200266 MGMT_STATUS_FAILED, /* Slot Violation */
267 MGMT_STATUS_FAILED, /* Role Switch Failed */
268 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
269 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
270 MGMT_STATUS_BUSY, /* Host Busy Pairing */
271 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
272 MGMT_STATUS_BUSY, /* Controller Busy */
273 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
274 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
275 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
276 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
277 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
278};
279
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700280static u8 mgmt_errno_status(int err)
Johan Hedbergca69b792011-11-11 18:10:00 +0200281{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700282 switch (err) {
283 case 0:
284 return MGMT_STATUS_SUCCESS;
285 case -EPERM:
286 return MGMT_STATUS_REJECTED;
287 case -EINVAL:
288 return MGMT_STATUS_INVALID_PARAMS;
289 case -EOPNOTSUPP:
290 return MGMT_STATUS_NOT_SUPPORTED;
291 case -EBUSY:
292 return MGMT_STATUS_BUSY;
293 case -ETIMEDOUT:
294 return MGMT_STATUS_AUTH_FAILED;
295 case -ENOMEM:
296 return MGMT_STATUS_NO_RESOURCES;
297 case -EISCONN:
298 return MGMT_STATUS_ALREADY_CONNECTED;
299 case -ENOTCONN:
300 return MGMT_STATUS_DISCONNECTED;
301 }
302
303 return MGMT_STATUS_FAILED;
304}
305
306static u8 mgmt_status(int err)
307{
308 if (err < 0)
309 return mgmt_errno_status(err);
310
311 if (err < ARRAY_SIZE(mgmt_status_table))
312 return mgmt_status_table[err];
Johan Hedbergca69b792011-11-11 18:10:00 +0200313
314 return MGMT_STATUS_FAILED;
315}
316
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700317static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
318 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700319{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700320 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
321 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700322}
323
Marcel Holtmann72000df2015-03-16 16:11:21 -0700324static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
325 u16 len, int flag, struct sock *skip_sk)
326{
327 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
328 flag, skip_sk);
329}
330
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200331static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
332 struct sock *skip_sk)
333{
334 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700335 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200336}
337
Johan Hedberg85813a72015-10-21 18:02:59 +0300338static u8 le_addr_type(u8 mgmt_addr_type)
339{
340 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
341 return ADDR_LE_DEV_PUBLIC;
342 else
343 return ADDR_LE_DEV_RANDOM;
344}
345
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200346void mgmt_fill_version_info(void *ver)
347{
348 struct mgmt_rp_read_version *rp = ver;
349
350 rp->version = MGMT_VERSION;
351 rp->revision = cpu_to_le16(MGMT_REVISION);
352}
353
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300354static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
355 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200356{
357 struct mgmt_rp_read_version rp;
358
Marcel Holtmann181d6952020-05-06 09:57:47 +0200359 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200360
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200361 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200362
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200363 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
364 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200365}
366
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300367static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
368 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200369{
370 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700371 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200372 size_t rp_size;
373 int i, err;
374
Marcel Holtmann181d6952020-05-06 09:57:47 +0200375 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200376
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700377 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
378 num_commands = ARRAY_SIZE(mgmt_commands);
379 num_events = ARRAY_SIZE(mgmt_events);
380 } else {
381 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
382 num_events = ARRAY_SIZE(mgmt_untrusted_events);
383 }
384
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200385 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
386
387 rp = kmalloc(rp_size, GFP_KERNEL);
388 if (!rp)
389 return -ENOMEM;
390
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700391 rp->num_commands = cpu_to_le16(num_commands);
392 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200393
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700394 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
395 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200396
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700397 for (i = 0; i < num_commands; i++, opcode++)
398 put_unaligned_le16(mgmt_commands[i], opcode);
399
400 for (i = 0; i < num_events; i++, opcode++)
401 put_unaligned_le16(mgmt_events[i], opcode);
402 } else {
403 __le16 *opcode = rp->opcodes;
404
405 for (i = 0; i < num_commands; i++, opcode++)
406 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
407
408 for (i = 0; i < num_events; i++, opcode++)
409 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
410 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200411
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200412 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
413 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200414 kfree(rp);
415
416 return err;
417}
418
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300419static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
420 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200421{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200422 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200423 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200424 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200425 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300426 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200427
Marcel Holtmann181d6952020-05-06 09:57:47 +0200428 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200429
430 read_lock(&hci_dev_list_lock);
431
432 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300433 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200434 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700436 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200437 }
438
Johan Hedberga38528f2011-01-22 06:46:43 +0200439 rp_len = sizeof(*rp) + (2 * count);
440 rp = kmalloc(rp_len, GFP_ATOMIC);
441 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100442 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200443 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100444 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200445
Johan Hedberg476e44c2012-10-19 20:10:46 +0300446 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200447 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700448 if (hci_dev_test_flag(d, HCI_SETUP) ||
449 hci_dev_test_flag(d, HCI_CONFIG) ||
450 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200451 continue;
452
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200453 /* Devices marked as raw-only are neither configured
454 * nor unconfigured controllers.
455 */
456 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700457 continue;
458
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200459 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700460 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700461 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200462 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700463 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200464 }
465
Johan Hedberg476e44c2012-10-19 20:10:46 +0300466 rp->num_controllers = cpu_to_le16(count);
467 rp_len = sizeof(*rp) + (2 * count);
468
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200469 read_unlock(&hci_dev_list_lock);
470
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200471 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
472 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200473
Johan Hedberga38528f2011-01-22 06:46:43 +0200474 kfree(rp);
475
476 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200477}
478
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200479static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
480 void *data, u16 data_len)
481{
482 struct mgmt_rp_read_unconf_index_list *rp;
483 struct hci_dev *d;
484 size_t rp_len;
485 u16 count;
486 int err;
487
Marcel Holtmann181d6952020-05-06 09:57:47 +0200488 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200489
490 read_lock(&hci_dev_list_lock);
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200494 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700495 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200496 count++;
497 }
498
499 rp_len = sizeof(*rp) + (2 * count);
500 rp = kmalloc(rp_len, GFP_ATOMIC);
501 if (!rp) {
502 read_unlock(&hci_dev_list_lock);
503 return -ENOMEM;
504 }
505
506 count = 0;
507 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700508 if (hci_dev_test_flag(d, HCI_SETUP) ||
509 hci_dev_test_flag(d, HCI_CONFIG) ||
510 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200511 continue;
512
513 /* Devices marked as raw-only are neither configured
514 * nor unconfigured controllers.
515 */
516 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
517 continue;
518
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200519 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700520 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200521 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200522 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200523 }
524 }
525
526 rp->num_controllers = cpu_to_le16(count);
527 rp_len = sizeof(*rp) + (2 * count);
528
529 read_unlock(&hci_dev_list_lock);
530
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200531 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
532 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200533
534 kfree(rp);
535
536 return err;
537}
538
Marcel Holtmann96f14742015-03-14 19:27:57 -0700539static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
540 void *data, u16 data_len)
541{
542 struct mgmt_rp_read_ext_index_list *rp;
543 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700544 u16 count;
545 int err;
546
Marcel Holtmann181d6952020-05-06 09:57:47 +0200547 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700548
549 read_lock(&hci_dev_list_lock);
550
551 count = 0;
552 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200553 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700554 count++;
555 }
556
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600557 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700558 if (!rp) {
559 read_unlock(&hci_dev_list_lock);
560 return -ENOMEM;
561 }
562
563 count = 0;
564 list_for_each_entry(d, &hci_dev_list, list) {
565 if (hci_dev_test_flag(d, HCI_SETUP) ||
566 hci_dev_test_flag(d, HCI_CONFIG) ||
567 hci_dev_test_flag(d, HCI_USER_CHANNEL))
568 continue;
569
570 /* Devices marked as raw-only are neither configured
571 * nor unconfigured controllers.
572 */
573 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
574 continue;
575
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200576 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700577 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
578 rp->entry[count].type = 0x01;
579 else
580 rp->entry[count].type = 0x00;
581 } else if (d->dev_type == HCI_AMP) {
582 rp->entry[count].type = 0x02;
583 } else {
584 continue;
585 }
586
587 rp->entry[count].bus = d->bus;
588 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200589 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700590 }
591
592 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700593
594 read_unlock(&hci_dev_list_lock);
595
596 /* If this command is called at least once, then all the
597 * default index and unconfigured index events are disabled
598 * and from now on only extended index events are used.
599 */
600 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
601 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
602 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
603
604 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600605 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
606 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700607
608 kfree(rp);
609
610 return err;
611}
612
Marcel Holtmanndbece372014-07-04 18:11:55 +0200613static bool is_configured(struct hci_dev *hdev)
614{
615 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700616 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200617 return false;
618
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800619 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
620 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200621 !bacmp(&hdev->public_addr, BDADDR_ANY))
622 return false;
623
624 return true;
625}
626
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200627static __le32 get_missing_options(struct hci_dev *hdev)
628{
629 u32 options = 0;
630
Marcel Holtmanndbece372014-07-04 18:11:55 +0200631 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700632 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200633 options |= MGMT_OPTION_EXTERNAL_CONFIG;
634
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800635 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
636 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200637 !bacmp(&hdev->public_addr, BDADDR_ANY))
638 options |= MGMT_OPTION_PUBLIC_ADDRESS;
639
640 return cpu_to_le32(options);
641}
642
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200643static int new_options(struct hci_dev *hdev, struct sock *skip)
644{
645 __le32 options = get_missing_options(hdev);
646
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200647 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
648 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200649}
650
Marcel Holtmanndbece372014-07-04 18:11:55 +0200651static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
652{
653 __le32 options = get_missing_options(hdev);
654
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200655 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
656 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200657}
658
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200659static int read_config_info(struct sock *sk, struct hci_dev *hdev,
660 void *data, u16 data_len)
661{
662 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200663 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200664
Marcel Holtmann181d6952020-05-06 09:57:47 +0200665 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200666
667 hci_dev_lock(hdev);
668
669 memset(&rp, 0, sizeof(rp));
670 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200671
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200672 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
673 options |= MGMT_OPTION_EXTERNAL_CONFIG;
674
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200675 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200676 options |= MGMT_OPTION_PUBLIC_ADDRESS;
677
678 rp.supported_options = cpu_to_le32(options);
679 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200680
681 hci_dev_unlock(hdev);
682
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200683 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
684 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200685}
686
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530687static u32 get_supported_phys(struct hci_dev *hdev)
688{
689 u32 supported_phys = 0;
690
691 if (lmp_bredr_capable(hdev)) {
692 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
693
694 if (hdev->features[0][0] & LMP_3SLOT)
695 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
696
697 if (hdev->features[0][0] & LMP_5SLOT)
698 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
699
700 if (lmp_edr_2m_capable(hdev)) {
701 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
702
703 if (lmp_edr_3slot_capable(hdev))
704 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
705
706 if (lmp_edr_5slot_capable(hdev))
707 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
708
709 if (lmp_edr_3m_capable(hdev)) {
710 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
711
712 if (lmp_edr_3slot_capable(hdev))
713 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
714
715 if (lmp_edr_5slot_capable(hdev))
716 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
717 }
718 }
719 }
720
721 if (lmp_le_capable(hdev)) {
722 supported_phys |= MGMT_PHY_LE_1M_TX;
723 supported_phys |= MGMT_PHY_LE_1M_RX;
724
725 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
726 supported_phys |= MGMT_PHY_LE_2M_TX;
727 supported_phys |= MGMT_PHY_LE_2M_RX;
728 }
729
730 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
731 supported_phys |= MGMT_PHY_LE_CODED_TX;
732 supported_phys |= MGMT_PHY_LE_CODED_RX;
733 }
734 }
735
736 return supported_phys;
737}
738
739static u32 get_selected_phys(struct hci_dev *hdev)
740{
741 u32 selected_phys = 0;
742
743 if (lmp_bredr_capable(hdev)) {
744 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
745
746 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
747 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
748
749 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
750 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
751
752 if (lmp_edr_2m_capable(hdev)) {
753 if (!(hdev->pkt_type & HCI_2DH1))
754 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
755
756 if (lmp_edr_3slot_capable(hdev) &&
757 !(hdev->pkt_type & HCI_2DH3))
758 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
759
760 if (lmp_edr_5slot_capable(hdev) &&
761 !(hdev->pkt_type & HCI_2DH5))
762 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
763
764 if (lmp_edr_3m_capable(hdev)) {
765 if (!(hdev->pkt_type & HCI_3DH1))
766 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
767
768 if (lmp_edr_3slot_capable(hdev) &&
769 !(hdev->pkt_type & HCI_3DH3))
770 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
771
772 if (lmp_edr_5slot_capable(hdev) &&
773 !(hdev->pkt_type & HCI_3DH5))
774 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
775 }
776 }
777 }
778
779 if (lmp_le_capable(hdev)) {
780 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
781 selected_phys |= MGMT_PHY_LE_1M_TX;
782
783 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
784 selected_phys |= MGMT_PHY_LE_1M_RX;
785
786 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
787 selected_phys |= MGMT_PHY_LE_2M_TX;
788
789 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
790 selected_phys |= MGMT_PHY_LE_2M_RX;
791
792 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
793 selected_phys |= MGMT_PHY_LE_CODED_TX;
794
795 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
796 selected_phys |= MGMT_PHY_LE_CODED_RX;
797 }
798
799 return selected_phys;
800}
801
802static u32 get_configurable_phys(struct hci_dev *hdev)
803{
804 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
805 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
806}
807
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200808static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200809{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200810 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200811
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200812 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300813 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800814 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300815 settings |= MGMT_SETTING_CONNECTABLE;
816 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200817
Andre Guedesed3fa312012-07-24 15:03:46 -0300818 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500819 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
820 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200821 settings |= MGMT_SETTING_BREDR;
822 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700823
824 if (lmp_ssp_capable(hdev)) {
825 settings |= MGMT_SETTING_SSP;
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -0700826 if (IS_ENABLED(CONFIG_BT_HS))
827 settings |= MGMT_SETTING_HS;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700828 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800829
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800830 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800831 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000832
Alain Michaud00bce3f2020-03-05 16:14:59 +0000833 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000834 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000835 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700836 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100837
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300838 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200839 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300840 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200841 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800842 settings |= MGMT_SETTING_STATIC_ADDRESS;
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -0700843 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300844 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200845
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200846 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
847 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200848 settings |= MGMT_SETTING_CONFIGURATION;
849
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530850 settings |= MGMT_SETTING_PHY_CONFIGURATION;
851
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200852 return settings;
853}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200854
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200855static u32 get_current_settings(struct hci_dev *hdev)
856{
857 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200858
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200859 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100860 settings |= MGMT_SETTING_POWERED;
861
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700862 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200863 settings |= MGMT_SETTING_CONNECTABLE;
864
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700865 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500866 settings |= MGMT_SETTING_FAST_CONNECTABLE;
867
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700868 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200869 settings |= MGMT_SETTING_DISCOVERABLE;
870
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700871 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300872 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200873
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700874 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200875 settings |= MGMT_SETTING_BREDR;
876
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700877 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200878 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200879
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700880 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200881 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200882
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700883 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200884 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200885
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700886 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200887 settings |= MGMT_SETTING_HS;
888
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700889 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300890 settings |= MGMT_SETTING_ADVERTISING;
891
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700892 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800893 settings |= MGMT_SETTING_SECURE_CONN;
894
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700895 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800896 settings |= MGMT_SETTING_DEBUG_KEYS;
897
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700898 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200899 settings |= MGMT_SETTING_PRIVACY;
900
Marcel Holtmann93690c22015-03-06 10:11:21 -0800901 /* The current setting for static address has two purposes. The
902 * first is to indicate if the static address will be used and
903 * the second is to indicate if it is actually set.
904 *
905 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700906 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800907 * address is actually used decides if the flag is set or not.
908 *
909 * For single mode LE only controllers and dual-mode controllers
910 * with BR/EDR disabled, the existence of the static address will
911 * be evaluated.
912 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700913 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700914 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800915 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
916 if (bacmp(&hdev->static_addr, BDADDR_ANY))
917 settings |= MGMT_SETTING_STATIC_ADDRESS;
918 }
919
Alain Michaud00bce3f2020-03-05 16:14:59 +0000920 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
921 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
922
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200923 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200924}
925
Johan Hedberg333ae952015-03-17 13:48:47 +0200926static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
927{
928 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
929}
930
Johan Hedbergf2252572015-11-18 12:49:20 +0200931u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300932{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200933 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300934
935 /* If there's a pending mgmt command the flags will not yet have
936 * their final values, so check for this first.
937 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200938 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300939 if (cmd) {
940 struct mgmt_mode *cp = cmd->param;
941 if (cp->val == 0x01)
942 return LE_AD_GENERAL;
943 else if (cp->val == 0x02)
944 return LE_AD_LIMITED;
945 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700946 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300947 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700948 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300949 return LE_AD_GENERAL;
950 }
951
952 return 0;
953}
954
Johan Hedbergf2252572015-11-18 12:49:20 +0200955bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700956{
957 struct mgmt_pending_cmd *cmd;
958
959 /* If there's a pending mgmt command the flag will not yet have
960 * it's final value, so check for this first.
961 */
962 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
963 if (cmd) {
964 struct mgmt_mode *cp = cmd->param;
965
966 return cp->val;
967 }
968
969 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
970}
971
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700972static int service_cache_sync(struct hci_dev *hdev, void *data)
973{
974 hci_update_eir_sync(hdev);
975 hci_update_class_sync(hdev);
976
977 return 0;
978}
979
Johan Hedberg7d785252011-12-15 00:47:39 +0200980static void service_cache_off(struct work_struct *work)
981{
982 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300983 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200984
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700985 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200986 return;
987
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700988 hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200989}
990
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -0700991static int rpa_expired_sync(struct hci_dev *hdev, void *data)
992{
993 /* The generation of a new RPA and programming it into the
994 * controller happens in the hci_req_enable_advertising()
995 * function.
996 */
997 if (ext_adv_capable(hdev))
998 return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
999 else
1000 return hci_enable_advertising_sync(hdev);
1001}
1002
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001003static void rpa_expired(struct work_struct *work)
1004{
1005 struct hci_dev *hdev = container_of(work, struct hci_dev,
1006 rpa_expired.work);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001007
Marcel Holtmann181d6952020-05-06 09:57:47 +02001008 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001009
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001010 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001011
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001012 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001013 return;
1014
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07001015 hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001016}
1017
Johan Hedberg6a919082012-02-28 06:17:26 +02001018static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001019{
Marcel Holtmann238be782015-03-13 02:11:06 -07001020 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001021 return;
1022
Johan Hedberg4f87da82012-03-02 19:55:56 +02001023 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001024 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001025
Johan Hedberg4f87da82012-03-02 19:55:56 +02001026 /* Non-mgmt controlled devices get this bit set
1027 * implicitly so that pairing works for them, however
1028 * for mgmt we require user-space to explicitly enable
1029 * it
1030 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001031 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001032}
1033
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001034static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001035 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001036{
1037 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001038
Marcel Holtmann181d6952020-05-06 09:57:47 +02001039 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001040
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001041 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001042
Johan Hedberg03811012010-12-08 00:21:06 +02001043 memset(&rp, 0, sizeof(rp));
1044
Johan Hedberg03811012010-12-08 00:21:06 +02001045 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001046
1047 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001048 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001049
1050 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1051 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1052
1053 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001054
1055 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001056 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001057
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001058 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001059
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001060 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1061 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001062}
1063
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001064static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1065{
1066 u16 eir_len = 0;
1067 size_t name_len;
1068
1069 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1070 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1071 hdev->dev_class, 3);
1072
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001073 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1074 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1075 hdev->appearance);
1076
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001077 name_len = strlen(hdev->dev_name);
1078 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1079 hdev->dev_name, name_len);
1080
1081 name_len = strlen(hdev->short_name);
1082 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1083 hdev->short_name, name_len);
1084
1085 return eir_len;
1086}
1087
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001088static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1089 void *data, u16 data_len)
1090{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001091 char buf[512];
1092 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001093 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001094
Marcel Holtmann181d6952020-05-06 09:57:47 +02001095 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001096
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001097 memset(&buf, 0, sizeof(buf));
1098
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001099 hci_dev_lock(hdev);
1100
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001101 bacpy(&rp->bdaddr, &hdev->bdaddr);
1102
1103 rp->version = hdev->hci_ver;
1104 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1105
1106 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1107 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001108
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001109
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001110 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001111 rp->eir_len = cpu_to_le16(eir_len);
1112
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001113 hci_dev_unlock(hdev);
1114
1115 /* If this command is called at least once, then the events
1116 * for class of device and local name changes are disabled
1117 * and only the new extended controller information event
1118 * is used.
1119 */
1120 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1121 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1122 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1123
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001124 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1125 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001126}
1127
1128static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1129{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001130 char buf[512];
1131 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1132 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001133
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001134 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001135
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001136 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1137 ev->eir_len = cpu_to_le16(eir_len);
1138
1139 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1140 sizeof(*ev) + eir_len,
1141 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001142}
1143
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001144static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001145{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001146 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001147
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001148 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1149 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001150}
1151
Johan Hedbergf2252572015-11-18 12:49:20 +02001152void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001153{
1154 struct mgmt_ev_advertising_added ev;
1155
1156 ev.instance = instance;
1157
1158 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1159}
1160
Johan Hedbergf2252572015-11-18 12:49:20 +02001161void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1162 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001163{
1164 struct mgmt_ev_advertising_removed ev;
1165
1166 ev.instance = instance;
1167
1168 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1169}
1170
Florian Grandel7816b822015-06-18 03:16:45 +02001171static void cancel_adv_timeout(struct hci_dev *hdev)
1172{
1173 if (hdev->adv_instance_timeout) {
1174 hdev->adv_instance_timeout = 0;
1175 cancel_delayed_work(&hdev->adv_instance_expire);
1176 }
1177}
1178
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001179/* This function requires the caller holds hdev->lock */
1180static void restart_le_actions(struct hci_dev *hdev)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001181{
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001182 struct hci_conn_params *p;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001183
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001184 list_for_each_entry(p, &hdev->le_conn_params, list) {
1185 /* Needed for AUTO_OFF case where might not "really"
1186 * have been powered off.
1187 */
1188 list_del_init(&p->action);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001189
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001190 switch (p->auto_connect) {
1191 case HCI_AUTO_CONN_DIRECT:
1192 case HCI_AUTO_CONN_ALWAYS:
1193 list_add(&p->action, &hdev->pend_le_conns);
1194 break;
1195 case HCI_AUTO_CONN_REPORT:
1196 list_add(&p->action, &hdev->pend_le_reports);
1197 break;
1198 default:
1199 break;
1200 }
1201 }
1202}
1203
1204static int new_settings(struct hci_dev *hdev, struct sock *skip)
1205{
1206 __le32 ev = cpu_to_le32(get_current_settings(hdev));
1207
1208 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1209 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
1210}
1211
1212static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
1213{
1214 struct mgmt_pending_cmd *cmd = data;
1215 struct mgmt_mode *cp = cmd->param;
1216
1217 bt_dev_dbg(hdev, "err %d", err);
1218
1219 if (!err) {
1220 if (cp->val) {
1221 hci_dev_lock(hdev);
1222 restart_le_actions(hdev);
1223 hci_update_passive_scan(hdev);
1224 hci_dev_unlock(hdev);
1225 }
1226
1227 send_settings_rsp(cmd->sk, cmd->opcode, hdev);
1228
1229 /* Only call new_setting for power on as power off is deferred
1230 * to hdev->power_off work which does call hci_dev_do_close.
1231 */
1232 if (cp->val)
1233 new_settings(hdev, cmd->sk);
1234 } else {
1235 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED,
1236 mgmt_status(err));
Johan Hedberg8b064a32014-02-24 14:52:22 +02001237 }
1238
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001239 mgmt_pending_free(cmd);
1240}
Arman Uguray912098a2015-03-23 15:57:15 -07001241
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001242static int set_powered_sync(struct hci_dev *hdev, void *data)
1243{
1244 struct mgmt_pending_cmd *cmd = data;
1245 struct mgmt_mode *cp = cmd->param;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001246
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001247 BT_DBG("%s", hdev->name);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001248
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001249 return hci_set_powered_sync(hdev, cp->val);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001250}
1251
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001252static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001253 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001254{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001255 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001256 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001257 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001258
Marcel Holtmann181d6952020-05-06 09:57:47 +02001259 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001260
Johan Hedberga7e80f22013-01-09 16:05:19 +02001261 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001262 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1263 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001264
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001265 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001266
Johan Hedberg333ae952015-03-17 13:48:47 +02001267 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001268 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1269 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001270 goto failed;
1271 }
1272
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001273 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001274 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001275 goto failed;
1276 }
1277
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001278 cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001279 if (!cmd) {
1280 err = -ENOMEM;
1281 goto failed;
1282 }
1283
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001284 err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
1285 mgmt_set_powered_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001286
1287failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001288 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001289 return err;
1290}
1291
Johan Hedberg91a668b2014-07-09 13:28:26 +03001292int mgmt_new_settings(struct hci_dev *hdev)
1293{
1294 return new_settings(hdev, NULL);
1295}
1296
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001297struct cmd_lookup {
1298 struct sock *sk;
1299 struct hci_dev *hdev;
1300 u8 mgmt_status;
1301};
1302
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001303static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001304{
1305 struct cmd_lookup *match = data;
1306
1307 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1308
1309 list_del(&cmd->list);
1310
1311 if (match->sk == NULL) {
1312 match->sk = cmd->sk;
1313 sock_hold(match->sk);
1314 }
1315
1316 mgmt_pending_free(cmd);
1317}
1318
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001319static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001320{
1321 u8 *status = data;
1322
Johan Hedberga69e8372015-03-06 21:08:53 +02001323 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001324 mgmt_pending_remove(cmd);
1325}
1326
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001327static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001328{
1329 if (cmd->cmd_complete) {
1330 u8 *status = data;
1331
1332 cmd->cmd_complete(cmd, *status);
1333 mgmt_pending_remove(cmd);
1334
1335 return;
1336 }
1337
1338 cmd_status_rsp(cmd, data);
1339}
1340
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001341static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001342{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001343 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1344 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001345}
1346
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001348{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001349 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1350 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001351}
1352
Johan Hedberge6fe7982013-10-02 15:45:22 +03001353static u8 mgmt_bredr_support(struct hci_dev *hdev)
1354{
1355 if (!lmp_bredr_capable(hdev))
1356 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001357 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001358 return MGMT_STATUS_REJECTED;
1359 else
1360 return MGMT_STATUS_SUCCESS;
1361}
1362
1363static u8 mgmt_le_support(struct hci_dev *hdev)
1364{
1365 if (!lmp_le_capable(hdev))
1366 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001367 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001368 return MGMT_STATUS_REJECTED;
1369 else
1370 return MGMT_STATUS_SUCCESS;
1371}
1372
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001373static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
1374 int err)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001375{
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001376 struct mgmt_pending_cmd *cmd = data;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001377
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001378 bt_dev_dbg(hdev, "err %d", err);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001379
1380 hci_dev_lock(hdev);
1381
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001382 if (err) {
1383 u8 mgmt_err = mgmt_status(err);
Johan Hedberga69e8372015-03-06 21:08:53 +02001384 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001385 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001386 goto done;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001387 }
1388
Johan Hedbergaed1a882015-11-22 17:24:44 +03001389 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1390 hdev->discov_timeout > 0) {
1391 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1392 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001393 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001394
1395 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001396 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001397
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001398done:
1399 mgmt_pending_free(cmd);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001400 hci_dev_unlock(hdev);
1401}
1402
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001403static int set_discoverable_sync(struct hci_dev *hdev, void *data)
1404{
1405 BT_DBG("%s", hdev->name);
1406
1407 return hci_update_discoverable_sync(hdev);
1408}
1409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001411 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001412{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001413 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001414 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001415 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001416 int err;
1417
Marcel Holtmann181d6952020-05-06 09:57:47 +02001418 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001419
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001420 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1421 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1423 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001424
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001425 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001426 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1427 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001428
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001429 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001430
1431 /* Disabling discoverable requires that no timeout is set,
1432 * and enabling limited discoverable requires a timeout.
1433 */
1434 if ((cp->val == 0x00 && timeout > 0) ||
1435 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001436 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1437 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001438
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001440
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001441 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001442 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1443 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001444 goto failed;
1445 }
1446
Johan Hedberg333ae952015-03-17 13:48:47 +02001447 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1448 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001449 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1450 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001451 goto failed;
1452 }
1453
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001454 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001455 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1456 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001457 goto failed;
1458 }
1459
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001460 if (hdev->advertising_paused) {
1461 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1462 MGMT_STATUS_BUSY);
1463 goto failed;
1464 }
1465
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001466 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001467 bool changed = false;
1468
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001469 /* Setting limited discoverable when powered off is
1470 * not a valid operation since it requires a timeout
1471 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1472 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001473 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001474 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001475 changed = true;
1476 }
1477
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001478 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001479 if (err < 0)
1480 goto failed;
1481
1482 if (changed)
1483 err = new_settings(hdev, sk);
1484
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001485 goto failed;
1486 }
1487
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001488 /* If the current mode is the same, then just update the timeout
1489 * value with the new value. And if only the timeout gets updated,
1490 * then no need for any HCI transactions.
1491 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001492 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1493 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1494 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001495 cancel_delayed_work(&hdev->discov_off);
1496 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001497
Marcel Holtmann36261542013-10-15 08:28:51 -07001498 if (cp->val && hdev->discov_timeout > 0) {
1499 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001500 queue_delayed_work(hdev->req_workqueue,
1501 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001502 }
1503
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001504 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505 goto failed;
1506 }
1507
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001508 cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001509 if (!cmd) {
1510 err = -ENOMEM;
1511 goto failed;
1512 }
1513
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001514 /* Cancel any potential discoverable timeout that might be
1515 * still active and store new timeout value. The arming of
1516 * the timeout happens in the complete handler.
1517 */
1518 cancel_delayed_work(&hdev->discov_off);
1519 hdev->discov_timeout = timeout;
1520
Johan Hedbergaed1a882015-11-22 17:24:44 +03001521 if (cp->val)
1522 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1523 else
1524 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1525
Johan Hedbergb456f872013-10-19 23:38:22 +03001526 /* Limited discoverable mode */
1527 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001528 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001529 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001530 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001531
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001532 err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd,
1533 mgmt_set_discoverable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001534
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001535failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001536 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001537 return err;
1538}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001539
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001540void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001541{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001542 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001543
Marcel Holtmann181d6952020-05-06 09:57:47 +02001544 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001545
1546 hci_dev_lock(hdev);
1547
Johan Hedberg333ae952015-03-17 13:48:47 +02001548 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001549 if (!cmd)
1550 goto unlock;
1551
Johan Hedberg37438c12013-10-14 16:20:05 +03001552 if (status) {
1553 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001554 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001555 goto remove_cmd;
1556 }
1557
Johan Hedberg2b76f452013-03-15 17:07:04 -05001558 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001559 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001560
Johan Hedberg37438c12013-10-14 16:20:05 +03001561remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001562 mgmt_pending_remove(cmd);
1563
1564unlock:
1565 hci_dev_unlock(hdev);
1566}
1567
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001568static int set_connectable_update_settings(struct hci_dev *hdev,
1569 struct sock *sk, u8 val)
1570{
1571 bool changed = false;
1572 int err;
1573
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001574 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001575 changed = true;
1576
1577 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001578 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001579 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001580 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1581 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001582 }
1583
1584 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1585 if (err < 0)
1586 return err;
1587
Johan Hedberg562064e2014-07-08 16:35:34 +03001588 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001589 hci_req_update_scan(hdev);
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07001590 hci_update_passive_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001591 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001592 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001593
1594 return 0;
1595}
1596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001598 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001599{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001600 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001601 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001602 int err;
1603
Marcel Holtmann181d6952020-05-06 09:57:47 +02001604 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001605
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001606 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1607 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001608 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1609 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001610
Johan Hedberga7e80f22013-01-09 16:05:19 +02001611 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001612 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1613 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001614
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001615 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001616
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001617 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001618 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001619 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001620 }
1621
Johan Hedberg333ae952015-03-17 13:48:47 +02001622 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1623 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001624 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1625 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001626 goto failed;
1627 }
1628
Johan Hedberg73f22f62010-12-29 16:00:25 +02001629 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1630 if (!cmd) {
1631 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001632 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001633 }
1634
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001635 if (cp->val) {
1636 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1637 } else {
1638 if (hdev->discov_timeout > 0)
1639 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001640
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001641 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1642 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1643 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001644 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001645
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001646 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1647 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001648
1649failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001650 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001651 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001652}
1653
Johan Hedbergb2939472014-07-30 09:22:23 +03001654static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001655 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001656{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001657 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001658 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001659 int err;
1660
Marcel Holtmann181d6952020-05-06 09:57:47 +02001661 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001662
Johan Hedberga7e80f22013-01-09 16:05:19 +02001663 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1665 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001666
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001667 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001668
1669 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001670 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001671 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001672 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001673
Johan Hedbergb2939472014-07-30 09:22:23 +03001674 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001675 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001676 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001677
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001678 if (changed) {
1679 /* In limited privacy mode the change of bondable mode
1680 * may affect the local advertising address.
1681 */
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001682 hci_update_discoverable(hdev);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001683
Marcel Holtmann55594352013-10-06 16:11:57 -07001684 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001685 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001686
Marcel Holtmann55594352013-10-06 16:11:57 -07001687unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001688 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001689 return err;
1690}
1691
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001692static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1693 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001694{
1695 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001696 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001697 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001698 int err;
1699
Marcel Holtmann181d6952020-05-06 09:57:47 +02001700 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001701
Johan Hedberge6fe7982013-10-02 15:45:22 +03001702 status = mgmt_bredr_support(hdev);
1703 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001704 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1705 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001706
Johan Hedberga7e80f22013-01-09 16:05:19 +02001707 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001708 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1709 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001710
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001711 hci_dev_lock(hdev);
1712
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001713 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001714 bool changed = false;
1715
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001716 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001717 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001718 changed = true;
1719 }
1720
1721 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1722 if (err < 0)
1723 goto failed;
1724
1725 if (changed)
1726 err = new_settings(hdev, sk);
1727
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001728 goto failed;
1729 }
1730
Johan Hedberg333ae952015-03-17 13:48:47 +02001731 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001732 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1733 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001734 goto failed;
1735 }
1736
1737 val = !!cp->val;
1738
1739 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1740 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1741 goto failed;
1742 }
1743
1744 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1745 if (!cmd) {
1746 err = -ENOMEM;
1747 goto failed;
1748 }
1749
1750 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1751 if (err < 0) {
1752 mgmt_pending_remove(cmd);
1753 goto failed;
1754 }
1755
1756failed:
1757 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001758 return err;
1759}
1760
Brian Gix32448452021-10-27 16:58:58 -07001761static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
1762{
1763 struct cmd_lookup match = { NULL, hdev };
1764 struct mgmt_pending_cmd *cmd = data;
1765 struct mgmt_mode *cp = cmd->param;
1766 u8 enable = cp->val;
1767 bool changed;
1768
1769 if (err) {
1770 u8 mgmt_err = mgmt_status(err);
1771
1772 if (enable && hci_dev_test_and_clear_flag(hdev,
1773 HCI_SSP_ENABLED)) {
1774 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
1775 new_settings(hdev, NULL);
1776 }
1777
1778 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
1779 &mgmt_err);
1780 return;
1781 }
1782
1783 if (enable) {
1784 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
1785 } else {
1786 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
1787
1788 if (!changed)
1789 changed = hci_dev_test_and_clear_flag(hdev,
1790 HCI_HS_ENABLED);
1791 else
1792 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
1793 }
1794
1795 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
1796
1797 if (changed)
1798 new_settings(hdev, match.sk);
1799
1800 if (match.sk)
1801 sock_put(match.sk);
1802
1803 hci_update_eir_sync(hdev);
1804}
1805
1806static int set_ssp_sync(struct hci_dev *hdev, void *data)
1807{
1808 struct mgmt_pending_cmd *cmd = data;
1809 struct mgmt_mode *cp = cmd->param;
1810 bool changed = false;
1811 int err;
1812
1813 if (cp->val)
1814 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
1815
1816 err = hci_write_ssp_mode_sync(hdev, cp->val);
1817
1818 if (!err && changed)
1819 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
1820
1821 return err;
1822}
1823
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001824static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001825{
1826 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001827 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001828 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001829 int err;
1830
Marcel Holtmann181d6952020-05-06 09:57:47 +02001831 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001832
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001833 status = mgmt_bredr_support(hdev);
1834 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001835 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001836
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001837 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001838 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1839 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001840
Johan Hedberga7e80f22013-01-09 16:05:19 +02001841 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001842 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1843 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001844
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001845 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001846
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001847 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001848 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001849
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001850 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001851 changed = !hci_dev_test_and_set_flag(hdev,
1852 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001853 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001854 changed = hci_dev_test_and_clear_flag(hdev,
1855 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001856 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001857 changed = hci_dev_test_and_clear_flag(hdev,
1858 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001859 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001860 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001861 }
1862
1863 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1864 if (err < 0)
1865 goto failed;
1866
1867 if (changed)
1868 err = new_settings(hdev, sk);
1869
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001870 goto failed;
1871 }
1872
Johan Hedberg333ae952015-03-17 13:48:47 +02001873 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001874 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1875 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001876 goto failed;
1877 }
1878
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001879 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001880 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1881 goto failed;
1882 }
1883
1884 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
Brian Gix32448452021-10-27 16:58:58 -07001885 if (!cmd)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001886 err = -ENOMEM;
Brian Gix32448452021-10-27 16:58:58 -07001887 else
1888 err = hci_cmd_sync_queue(hdev, set_ssp_sync, cmd,
1889 set_ssp_complete);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001890
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001891 if (err < 0) {
Brian Gix32448452021-10-27 16:58:58 -07001892 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1893 MGMT_STATUS_FAILED);
1894
1895 if (cmd)
1896 mgmt_pending_remove(cmd);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001897 }
1898
1899failed:
1900 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001901 return err;
1902}
1903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001905{
1906 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001907 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001908 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001909 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001910
Marcel Holtmann181d6952020-05-06 09:57:47 +02001911 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001912
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -07001913 if (!IS_ENABLED(CONFIG_BT_HS))
1914 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1915 MGMT_STATUS_NOT_SUPPORTED);
1916
Johan Hedberge6fe7982013-10-02 15:45:22 +03001917 status = mgmt_bredr_support(hdev);
1918 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001919 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001920
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001921 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001922 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1923 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001924
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001925 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001926 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1927 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001928
Johan Hedberga7e80f22013-01-09 16:05:19 +02001929 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1931 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001932
Marcel Holtmannee392692013-10-01 22:59:23 -07001933 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001934
Johan Hedberg333ae952015-03-17 13:48:47 +02001935 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001936 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1937 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001938 goto unlock;
1939 }
1940
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001941 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001942 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001943 } else {
1944 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001945 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1946 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001947 goto unlock;
1948 }
1949
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001950 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001951 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001952
1953 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1954 if (err < 0)
1955 goto unlock;
1956
1957 if (changed)
1958 err = new_settings(hdev, sk);
1959
1960unlock:
1961 hci_dev_unlock(hdev);
1962 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001963}
1964
Brian Gixd81a4942021-10-27 16:58:51 -07001965static void set_le_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001966{
1967 struct cmd_lookup match = { NULL, hdev };
Brian Gixd81a4942021-10-27 16:58:51 -07001968 u8 status = mgmt_status(err);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001969
Brian Gixd81a4942021-10-27 16:58:51 -07001970 bt_dev_dbg(hdev, "err %d", err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301971
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001972 if (status) {
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001973 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
Brian Gixd81a4942021-10-27 16:58:51 -07001974 &status);
1975 return;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001976 }
1977
1978 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1979
1980 new_settings(hdev, match.sk);
1981
1982 if (match.sk)
1983 sock_put(match.sk);
Brian Gixd81a4942021-10-27 16:58:51 -07001984}
1985
1986static int set_le_sync(struct hci_dev *hdev, void *data)
1987{
1988 struct mgmt_pending_cmd *cmd = data;
1989 struct mgmt_mode *cp = cmd->param;
1990 u8 val = !!cp->val;
1991 int err;
1992
1993 if (!val) {
1994 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
1995 hci_disable_advertising_sync(hdev);
1996
1997 if (ext_adv_capable(hdev))
1998 hci_remove_ext_adv_instance_sync(hdev, 0, cmd->sk);
1999 } else {
2000 hci_dev_set_flag(hdev, HCI_LE_ENABLED);
2001 }
2002
2003 err = hci_write_le_host_supported_sync(hdev, val, 0);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002004
2005 /* Make sure the controller has a good default for
2006 * advertising data. Restrict the update to when LE
2007 * has actually been enabled. During power on, the
2008 * update in powered_update_hci will take care of it.
2009 */
Brian Gixd81a4942021-10-27 16:58:51 -07002010 if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302011 if (ext_adv_capable(hdev)) {
Brian Gixd81a4942021-10-27 16:58:51 -07002012 int status;
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302013
Brian Gixd81a4942021-10-27 16:58:51 -07002014 status = hci_setup_ext_adv_instance_sync(hdev, 0x00);
2015 if (!status)
2016 hci_update_scan_rsp_data_sync(hdev, 0x00);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302017 } else {
Brian Gixd81a4942021-10-27 16:58:51 -07002018 hci_update_adv_data_sync(hdev, 0x00);
2019 hci_update_scan_rsp_data_sync(hdev, 0x00);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302020 }
Brian Gixd81a4942021-10-27 16:58:51 -07002021
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07002022 hci_update_passive_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002023 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302024
Brian Gixd81a4942021-10-27 16:58:51 -07002025 return err;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002026}
2027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002029{
2030 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002031 struct mgmt_pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002032 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002033 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002034
Marcel Holtmann181d6952020-05-06 09:57:47 +02002035 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002036
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002037 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002038 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2039 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002040
Johan Hedberga7e80f22013-01-09 16:05:19 +02002041 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002042 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2043 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002044
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002045 /* Bluetooth single mode LE only controllers or dual-mode
2046 * controllers configured as LE only devices, do not allow
2047 * switching LE off. These have either LE enabled explicitly
2048 * or BR/EDR has been previously switched off.
2049 *
2050 * When trying to enable an already enabled LE, then gracefully
2051 * send a positive response. Trying to disable it however will
2052 * result into rejection.
2053 */
2054 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
2055 if (cp->val == 0x01)
2056 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2057
Johan Hedberga69e8372015-03-06 21:08:53 +02002058 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2059 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002060 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03002061
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002062 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002063
2064 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002065 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002066
Florian Grandel847818d2015-06-18 03:16:46 +02002067 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03002068 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02002069
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002070 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002071 bool changed = false;
2072
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002073 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002074 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002075 changed = true;
2076 }
2077
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002078 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002079 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002080 changed = true;
2081 }
2082
Johan Hedberg06199cf2012-02-22 16:37:11 +02002083 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2084 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002085 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002086
2087 if (changed)
2088 err = new_settings(hdev, sk);
2089
Johan Hedberg1de028c2012-02-29 19:55:35 -08002090 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002091 }
2092
Johan Hedberg333ae952015-03-17 13:48:47 +02002093 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2094 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002095 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2096 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002097 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002098 }
2099
2100 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
Brian Gixd81a4942021-10-27 16:58:51 -07002101 if (!cmd)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002102 err = -ENOMEM;
Brian Gixd81a4942021-10-27 16:58:51 -07002103 else
2104 err = hci_cmd_sync_queue(hdev, set_le_sync, cmd,
2105 set_le_complete);
2106
2107 if (err < 0) {
2108 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2109 MGMT_STATUS_FAILED);
2110
2111 if (cmd)
2112 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002113 }
2114
Johan Hedberg1de028c2012-02-29 19:55:35 -08002115unlock:
2116 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002117 return err;
2118}
2119
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002120/* This is a helper function to test for pending mgmt commands that can
2121 * cause CoD or EIR HCI commands. We can only allow one such pending
2122 * mgmt command at a time since otherwise we cannot easily track what
2123 * the current values are, will be, and based on that calculate if a new
2124 * HCI command needs to be sent and if yes with what value.
2125 */
2126static bool pending_eir_or_class(struct hci_dev *hdev)
2127{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002128 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002129
2130 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2131 switch (cmd->opcode) {
2132 case MGMT_OP_ADD_UUID:
2133 case MGMT_OP_REMOVE_UUID:
2134 case MGMT_OP_SET_DEV_CLASS:
2135 case MGMT_OP_SET_POWERED:
2136 return true;
2137 }
2138 }
2139
2140 return false;
2141}
2142
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002143static const u8 bluetooth_base_uuid[] = {
2144 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2145 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2146};
2147
2148static u8 get_uuid_size(const u8 *uuid)
2149{
2150 u32 val;
2151
2152 if (memcmp(uuid, bluetooth_base_uuid, 12))
2153 return 128;
2154
2155 val = get_unaligned_le32(&uuid[12]);
2156 if (val > 0xffff)
2157 return 32;
2158
2159 return 16;
2160}
2161
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002162static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg92da6092013-03-15 17:06:55 -05002163{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002164 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg92da6092013-03-15 17:06:55 -05002165
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002166 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg92da6092013-03-15 17:06:55 -05002167
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002168 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002169 mgmt_status(err), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002170
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002171 mgmt_pending_free(cmd);
Johan Hedberg92da6092013-03-15 17:06:55 -05002172}
2173
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002174static int add_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002175{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002176 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002177
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002178 err = hci_update_class_sync(hdev);
2179 if (err)
2180 return err;
2181
2182 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002183}
2184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002186{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002187 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002188 struct mgmt_pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002190 int err;
2191
Marcel Holtmann181d6952020-05-06 09:57:47 +02002192 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002195
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002196 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002197 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2198 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002199 goto failed;
2200 }
2201
Andre Guedes92c4c202012-06-07 19:05:44 -03002202 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002203 if (!uuid) {
2204 err = -ENOMEM;
2205 goto failed;
2206 }
2207
2208 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002209 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002210 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002211
Johan Hedbergde66aa62013-01-27 00:31:27 +02002212 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002213
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002214 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002215 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002216 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002217 goto failed;
2218 }
2219
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002220 err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete);
2221 if (err < 0) {
2222 mgmt_pending_free(cmd);
2223 goto failed;
2224 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002225
2226failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002228 return err;
2229}
2230
Johan Hedberg24b78d02012-02-23 23:24:30 +02002231static bool enable_service_cache(struct hci_dev *hdev)
2232{
2233 if (!hdev_is_powered(hdev))
2234 return false;
2235
Marcel Holtmann238be782015-03-13 02:11:06 -07002236 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002237 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2238 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002239 return true;
2240 }
2241
2242 return false;
2243}
2244
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002245static int remove_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002246{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002247 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002248
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002249 err = hci_update_class_sync(hdev);
2250 if (err)
2251 return err;
2252
2253 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002254}
2255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002257 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002258{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002259 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002260 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002261 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002262 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 +02002263 int err, found;
2264
Marcel Holtmann181d6952020-05-06 09:57:47 +02002265 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002267 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002268
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002269 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002270 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2271 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002272 goto unlock;
2273 }
2274
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002275 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002276 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002277
Johan Hedberg24b78d02012-02-23 23:24:30 +02002278 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002279 err = mgmt_cmd_complete(sk, hdev->id,
2280 MGMT_OP_REMOVE_UUID,
2281 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002282 goto unlock;
2283 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002284
Johan Hedberg9246a862012-02-23 21:33:16 +02002285 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002286 }
2287
2288 found = 0;
2289
Johan Hedberg056341c2013-01-27 00:31:30 +02002290 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002291 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2292 continue;
2293
2294 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002295 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002296 found++;
2297 }
2298
2299 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002300 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002302 goto unlock;
2303 }
2304
Johan Hedberg9246a862012-02-23 21:33:16 +02002305update_class:
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002306 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002307 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002308 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002309 goto unlock;
2310 }
2311
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002312 err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd,
2313 mgmt_class_complete);
2314 if (err < 0)
2315 mgmt_pending_free(cmd);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002316
2317unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002318 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002319 return err;
2320}
2321
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002322static int set_class_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002323{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002324 int err = 0;
Johan Hedberg92da6092013-03-15 17:06:55 -05002325
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002326 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
2327 cancel_delayed_work_sync(&hdev->service_cache);
2328 err = hci_update_eir_sync(hdev);
2329 }
2330
2331 if (err)
2332 return err;
2333
2334 return hci_update_class_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002335}
2336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002337static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002338 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002339{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002340 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002341 struct mgmt_pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002342 int err;
2343
Marcel Holtmann181d6952020-05-06 09:57:47 +02002344 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002345
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002346 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002347 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2348 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002349
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002350 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002351
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002352 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002353 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2354 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002355 goto unlock;
2356 }
2357
2358 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002359 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002361 goto unlock;
2362 }
2363
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002364 hdev->major_class = cp->major;
2365 hdev->minor_class = cp->minor;
2366
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002367 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002368 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2369 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002370 goto unlock;
2371 }
2372
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002373 cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002374 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002375 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002376 goto unlock;
2377 }
2378
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002379 err = hci_cmd_sync_queue(hdev, set_class_sync, cmd,
2380 mgmt_class_complete);
2381 if (err < 0)
2382 mgmt_pending_free(cmd);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002383
Johan Hedbergb5235a62012-02-21 14:32:24 +02002384unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002385 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002386 return err;
2387}
2388
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002389static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002390 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002391{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002392 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002393 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2394 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002395 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002396 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002397 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002398
Marcel Holtmann181d6952020-05-06 09:57:47 +02002399 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002400
2401 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002402 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2403 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002404
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002405 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002406 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002407 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2408 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2410 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002411 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002412
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002413 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002414 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002415 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2416 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002417 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2418 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002419 }
2420
Johan Hedberg4ae143012013-01-20 14:27:13 +02002421 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2423 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002424
Marcel Holtmann181d6952020-05-06 09:57:47 +02002425 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2426 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002427
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002428 for (i = 0; i < key_count; i++) {
2429 struct mgmt_link_key_info *key = &cp->keys[i];
2430
Marcel Holtmann8e991132014-01-10 02:07:25 -08002431 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002432 return mgmt_cmd_status(sk, hdev->id,
2433 MGMT_OP_LOAD_LINK_KEYS,
2434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002435 }
2436
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002437 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002438
2439 hci_link_keys_clear(hdev);
2440
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002441 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002442 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002443 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002444 changed = hci_dev_test_and_clear_flag(hdev,
2445 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002446
2447 if (changed)
2448 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002449
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002450 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002451 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002452
Alain Michaud600a8742020-01-07 00:43:17 +00002453 if (hci_is_blocked_key(hdev,
2454 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2455 key->val)) {
2456 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2457 &key->addr.bdaddr);
2458 continue;
2459 }
2460
Johan Hedberg58e92932014-06-24 14:00:26 +03002461 /* Always ignore debug keys and require a new pairing if
2462 * the user wants to use them.
2463 */
2464 if (key->type == HCI_LK_DEBUG_COMBINATION)
2465 continue;
2466
Johan Hedberg7652ff62014-06-24 13:15:49 +03002467 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2468 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002469 }
2470
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002471 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002472
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002473 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002474
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002475 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002476}
2477
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002478static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002479 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002480{
2481 struct mgmt_ev_device_unpaired ev;
2482
2483 bacpy(&ev.addr.bdaddr, bdaddr);
2484 ev.addr.type = addr_type;
2485
2486 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002487 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002488}
2489
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002490static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002491 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002492{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002493 struct mgmt_cp_unpair_device *cp = data;
2494 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002495 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002496 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002497 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002498 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002499 int err;
2500
Johan Hedberga8a1d192011-11-10 15:54:38 +02002501 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002502 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2503 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002504
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002505 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002506 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2507 MGMT_STATUS_INVALID_PARAMS,
2508 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002509
Johan Hedberg118da702013-01-20 14:27:20 +02002510 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002511 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2512 MGMT_STATUS_INVALID_PARAMS,
2513 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002514
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002515 hci_dev_lock(hdev);
2516
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002517 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002518 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2519 MGMT_STATUS_NOT_POWERED, &rp,
2520 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002521 goto unlock;
2522 }
2523
Johan Hedberge0b2b272014-02-18 17:14:31 +02002524 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002525 /* If disconnection is requested, then look up the
2526 * connection. If the remote device is connected, it
2527 * will be later used to terminate the link.
2528 *
2529 * Setting it to NULL explicitly will cause no
2530 * termination of the link.
2531 */
2532 if (cp->disconnect)
2533 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2534 &cp->addr.bdaddr);
2535 else
2536 conn = NULL;
2537
Johan Hedberg124f6e32012-02-09 13:50:12 +02002538 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002539 if (err < 0) {
2540 err = mgmt_cmd_complete(sk, hdev->id,
2541 MGMT_OP_UNPAIR_DEVICE,
2542 MGMT_STATUS_NOT_PAIRED, &rp,
2543 sizeof(rp));
2544 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002545 }
2546
Johan Hedbergec182f02015-10-21 18:03:03 +03002547 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002548 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002549
Johan Hedbergec182f02015-10-21 18:03:03 +03002550 /* LE address type */
2551 addr_type = le_addr_type(cp->addr.type);
2552
Matias Karhumaacb28c302018-09-26 09:13:46 +03002553 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2554 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002555 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002556 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2557 MGMT_STATUS_NOT_PAIRED, &rp,
2558 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002559 goto unlock;
2560 }
2561
Johan Hedbergec182f02015-10-21 18:03:03 +03002562 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2563 if (!conn) {
2564 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2565 goto done;
2566 }
2567
Johan Hedbergc81d5552015-10-22 09:38:35 +03002568
Johan Hedbergec182f02015-10-21 18:03:03 +03002569 /* Defer clearing up the connection parameters until closing to
2570 * give a chance of keeping them if a repairing happens.
2571 */
2572 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2573
Johan Hedbergfc643612015-10-22 09:38:31 +03002574 /* Disable auto-connection parameters if present */
2575 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2576 if (params) {
2577 if (params->explicit_connect)
2578 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2579 else
2580 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2581 }
2582
Johan Hedbergec182f02015-10-21 18:03:03 +03002583 /* If disconnection is not requested, then clear the connection
2584 * variable so that the link is not terminated.
2585 */
2586 if (!cp->disconnect)
2587 conn = NULL;
2588
2589done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002590 /* If the connection variable is set, then termination of the
2591 * link is requested.
2592 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002593 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002594 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2595 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002596 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002597 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002598 }
2599
Johan Hedberg124f6e32012-02-09 13:50:12 +02002600 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002601 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002602 if (!cmd) {
2603 err = -ENOMEM;
2604 goto unlock;
2605 }
2606
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002607 cmd->cmd_complete = addr_cmd_complete;
2608
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002609 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002610 if (err < 0)
2611 mgmt_pending_remove(cmd);
2612
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002613unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002614 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002615 return err;
2616}
2617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002621 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002622 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002623 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002624 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002625 int err;
2626
Marcel Holtmann181d6952020-05-06 09:57:47 +02002627 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002628
Johan Hedberg06a63b12013-01-20 14:27:21 +02002629 memset(&rp, 0, sizeof(rp));
2630 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2631 rp.addr.type = cp->addr.type;
2632
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002633 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002634 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2635 MGMT_STATUS_INVALID_PARAMS,
2636 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002638 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002639
2640 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002641 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2642 MGMT_STATUS_NOT_POWERED, &rp,
2643 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002644 goto failed;
2645 }
2646
Johan Hedberg333ae952015-03-17 13:48:47 +02002647 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002648 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2649 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002650 goto failed;
2651 }
2652
Andre Guedes591f47f2012-04-24 21:02:49 -03002653 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002654 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2655 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002656 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002657 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2658 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002659
Vishal Agarwalf9607272012-06-13 05:32:43 +05302660 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002661 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2662 MGMT_STATUS_NOT_CONNECTED, &rp,
2663 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002664 goto failed;
2665 }
2666
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002667 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002668 if (!cmd) {
2669 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002670 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002671 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002672
Johan Hedbergf5818c22014-12-05 13:36:02 +02002673 cmd->cmd_complete = generic_cmd_complete;
2674
Johan Hedberge3f2f922014-08-18 20:33:33 +03002675 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002676 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002677 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002678
2679failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002680 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002681 return err;
2682}
2683
Andre Guedes57c14772012-04-24 21:02:50 -03002684static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002685{
2686 switch (link_type) {
2687 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002688 switch (addr_type) {
2689 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002690 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002691
Johan Hedberg48264f02011-11-09 13:58:58 +02002692 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002693 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002694 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002695 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002696
Johan Hedberg4c659c32011-11-07 23:13:39 +02002697 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002698 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002699 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002700 }
2701}
2702
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2704 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002705{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002706 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002707 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002708 int err;
2709 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002710
Marcel Holtmann181d6952020-05-06 09:57:47 +02002711 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002713 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002714
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002715 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002716 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2717 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002718 goto unlock;
2719 }
2720
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002721 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002722 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2723 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002724 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002725 }
2726
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002727 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002728 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002729 err = -ENOMEM;
2730 goto unlock;
2731 }
2732
Johan Hedberg2784eb42011-01-21 13:56:35 +02002733 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002734 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002735 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2736 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002737 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002738 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002739 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002740 continue;
2741 i++;
2742 }
2743
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002744 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002745
Johan Hedberg4c659c32011-11-07 23:13:39 +02002746 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002747 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002748 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002749
Johan Hedberga38528f2011-01-22 06:46:43 +02002750 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002751
2752unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002753 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002754 return err;
2755}
2756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002757static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002758 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002759{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002760 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002761 int err;
2762
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002763 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002764 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002765 if (!cmd)
2766 return -ENOMEM;
2767
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002768 cmd->cmd_complete = addr_cmd_complete;
2769
Johan Hedbergd8457692012-02-17 14:24:57 +02002770 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002771 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002772 if (err < 0)
2773 mgmt_pending_remove(cmd);
2774
2775 return err;
2776}
2777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002780{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002781 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002782 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002783 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002784 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002785 int err;
2786
Marcel Holtmann181d6952020-05-06 09:57:47 +02002787 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002789 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002790
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002791 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002792 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2793 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002794 goto failed;
2795 }
2796
Johan Hedbergd8457692012-02-17 14:24:57 +02002797 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002798 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002799 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2800 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002801 goto failed;
2802 }
2803
2804 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002805 struct mgmt_cp_pin_code_neg_reply ncp;
2806
2807 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002808
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002809 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002811 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002812 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002813 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2814 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002815
2816 goto failed;
2817 }
2818
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002819 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002820 if (!cmd) {
2821 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002822 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002823 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002824
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002825 cmd->cmd_complete = addr_cmd_complete;
2826
Johan Hedbergd8457692012-02-17 14:24:57 +02002827 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002828 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002829 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002830
2831 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2832 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002833 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002834
2835failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002836 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002837 return err;
2838}
2839
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002840static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2841 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002843 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002844
Marcel Holtmann181d6952020-05-06 09:57:47 +02002845 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002846
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002847 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002848 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002851 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002852
2853 hdev->io_capability = cp->io_capability;
2854
Marcel Holtmann181d6952020-05-06 09:57:47 +02002855 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002857 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002858
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002859 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2860 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002861}
2862
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002863static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002864{
2865 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002866 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002867
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002868 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002869 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2870 continue;
2871
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872 if (cmd->user_data != conn)
2873 continue;
2874
2875 return cmd;
2876 }
2877
2878 return NULL;
2879}
2880
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002881static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002882{
2883 struct mgmt_rp_pair_device rp;
2884 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002885 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002886
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002887 bacpy(&rp.addr.bdaddr, &conn->dst);
2888 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002889
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002890 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2891 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002892
2893 /* So we don't get further callbacks for this connection */
2894 conn->connect_cfm_cb = NULL;
2895 conn->security_cfm_cb = NULL;
2896 conn->disconn_cfm_cb = NULL;
2897
David Herrmann76a68ba2013-04-06 20:28:37 +02002898 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002899
2900 /* The device is paired so there is no need to remove
2901 * its connection parameters anymore.
2902 */
2903 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002904
2905 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002906
2907 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002908}
2909
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002910void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2911{
2912 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002913 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002914
2915 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002916 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002917 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002918 mgmt_pending_remove(cmd);
2919 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002920}
2921
Johan Hedberge9a416b2011-02-19 12:05:56 -03002922static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2923{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002924 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002925
2926 BT_DBG("status %u", status);
2927
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002928 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002929 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002930 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002931 return;
2932 }
2933
2934 cmd->cmd_complete(cmd, mgmt_status(status));
2935 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002936}
2937
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002938static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302939{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002940 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302941
2942 BT_DBG("status %u", status);
2943
2944 if (!status)
2945 return;
2946
2947 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002948 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302949 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002950 return;
2951 }
2952
2953 cmd->cmd_complete(cmd, mgmt_status(status));
2954 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302955}
2956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002959{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002961 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002962 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002963 u8 sec_level, auth_type;
2964 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002965 int err;
2966
Marcel Holtmann181d6952020-05-06 09:57:47 +02002967 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002968
Szymon Jancf950a30e2013-01-18 12:48:07 +01002969 memset(&rp, 0, sizeof(rp));
2970 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2971 rp.addr.type = cp->addr.type;
2972
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002973 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002974 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2975 MGMT_STATUS_INVALID_PARAMS,
2976 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002977
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002978 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002979 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2980 MGMT_STATUS_INVALID_PARAMS,
2981 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002982
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002983 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002984
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002985 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002986 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2987 MGMT_STATUS_NOT_POWERED, &rp,
2988 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002989 goto unlock;
2990 }
2991
Johan Hedberg55e76b32015-03-10 22:34:40 +02002992 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2993 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2994 MGMT_STATUS_ALREADY_PAIRED, &rp,
2995 sizeof(rp));
2996 goto unlock;
2997 }
2998
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002999 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003000 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003001
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003002 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003003 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02003004 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003005 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03003006 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003007 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003008
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003009 /* When pairing a new device, it is expected to remember
3010 * this device for future connections. Adding the connection
3011 * parameter information ahead of time allows tracking
Archie Pusaka67ffb182021-05-31 16:37:28 +08003012 * of the peripheral preferred values and will speed up any
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003013 * further connection establishment.
3014 *
3015 * If connection parameters already exist, then they
3016 * will be kept and this function does nothing.
3017 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003018 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3019
3020 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
3021 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003022
Manish Mandlik76b13992020-06-17 16:39:19 +02003023 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
3024 sec_level, HCI_LE_CONN_TIMEOUT,
3025 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003026 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003027
Ville Tervo30e76272011-02-22 16:10:53 -03003028 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003029 int status;
3030
3031 if (PTR_ERR(conn) == -EBUSY)
3032 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003033 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3034 status = MGMT_STATUS_NOT_SUPPORTED;
3035 else if (PTR_ERR(conn) == -ECONNREFUSED)
3036 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003037 else
3038 status = MGMT_STATUS_CONNECT_FAILED;
3039
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003040 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3041 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003042 goto unlock;
3043 }
3044
3045 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003046 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003047 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3048 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003049 goto unlock;
3050 }
3051
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003052 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003053 if (!cmd) {
3054 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003055 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003056 goto unlock;
3057 }
3058
Johan Hedberg04ab2742014-12-05 13:36:04 +02003059 cmd->cmd_complete = pairing_complete;
3060
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003061 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003062 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003063 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003064 conn->security_cfm_cb = pairing_complete_cb;
3065 conn->disconn_cfm_cb = pairing_complete_cb;
3066 } else {
3067 conn->connect_cfm_cb = le_pairing_complete_cb;
3068 conn->security_cfm_cb = le_pairing_complete_cb;
3069 conn->disconn_cfm_cb = le_pairing_complete_cb;
3070 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003071
Johan Hedberge9a416b2011-02-19 12:05:56 -03003072 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003073 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003074
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003075 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003076 hci_conn_security(conn, sec_level, auth_type, true)) {
3077 cmd->cmd_complete(cmd, 0);
3078 mgmt_pending_remove(cmd);
3079 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003080
3081 err = 0;
3082
3083unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003084 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003085 return err;
3086}
3087
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3089 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003090{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003091 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003092 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003093 struct hci_conn *conn;
3094 int err;
3095
Marcel Holtmann181d6952020-05-06 09:57:47 +02003096 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003097
Johan Hedberg28424702012-02-02 04:02:29 +02003098 hci_dev_lock(hdev);
3099
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003100 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003101 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3102 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003103 goto unlock;
3104 }
3105
Johan Hedberg333ae952015-03-17 13:48:47 +02003106 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003107 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003108 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3109 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003110 goto unlock;
3111 }
3112
3113 conn = cmd->user_data;
3114
3115 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003116 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3117 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003118 goto unlock;
3119 }
3120
Johan Hedberga511b352014-12-11 21:45:45 +02003121 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3122 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003123
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003124 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3125 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003126
3127 /* Since user doesn't want to proceed with the connection, abort any
3128 * ongoing pairing and then terminate the link if it was created
3129 * because of the pair device action.
3130 */
3131 if (addr->type == BDADDR_BREDR)
3132 hci_remove_link_key(hdev, &addr->bdaddr);
3133 else
3134 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3135 le_addr_type(addr->type));
3136
3137 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3138 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3139
Johan Hedberg28424702012-02-02 04:02:29 +02003140unlock:
3141 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003142 return err;
3143}
3144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003145static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003146 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003148{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003149 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003150 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003151 int err;
3152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003153 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003154
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003155 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003156 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3157 MGMT_STATUS_NOT_POWERED, addr,
3158 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003159 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003160 }
3161
Johan Hedberg1707c602013-03-15 17:07:15 -05003162 if (addr->type == BDADDR_BREDR)
3163 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003164 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003165 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3166 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003167
Johan Hedberg272d90d2012-02-09 15:26:12 +02003168 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003169 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3170 MGMT_STATUS_NOT_CONNECTED, addr,
3171 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 goto done;
3173 }
3174
Johan Hedberg1707c602013-03-15 17:07:15 -05003175 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003176 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003177 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003178 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3179 MGMT_STATUS_SUCCESS, addr,
3180 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003181 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003182 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3183 MGMT_STATUS_FAILED, addr,
3184 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003185
Brian Gix47c15e22011-11-16 13:53:14 -08003186 goto done;
3187 }
3188
Johan Hedberg1707c602013-03-15 17:07:15 -05003189 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003190 if (!cmd) {
3191 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003192 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003193 }
3194
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003195 cmd->cmd_complete = addr_cmd_complete;
3196
Brian Gix0df4c182011-11-16 13:53:13 -08003197 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003198 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3199 struct hci_cp_user_passkey_reply cp;
3200
Johan Hedberg1707c602013-03-15 17:07:15 -05003201 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003202 cp.passkey = passkey;
3203 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3204 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003205 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3206 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003207
Johan Hedberga664b5b2011-02-19 12:06:02 -03003208 if (err < 0)
3209 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003210
Brian Gix0df4c182011-11-16 13:53:13 -08003211done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003212 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003213 return err;
3214}
3215
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303216static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3217 void *data, u16 len)
3218{
3219 struct mgmt_cp_pin_code_neg_reply *cp = data;
3220
Marcel Holtmann181d6952020-05-06 09:57:47 +02003221 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303222
Johan Hedberg1707c602013-03-15 17:07:15 -05003223 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303224 MGMT_OP_PIN_CODE_NEG_REPLY,
3225 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3226}
3227
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003228static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3229 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003230{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003231 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003232
Marcel Holtmann181d6952020-05-06 09:57:47 +02003233 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003234
3235 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003236 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3237 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003238
Johan Hedberg1707c602013-03-15 17:07:15 -05003239 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003240 MGMT_OP_USER_CONFIRM_REPLY,
3241 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003242}
3243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003244static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003245 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003246{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003247 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003248
Marcel Holtmann181d6952020-05-06 09:57:47 +02003249 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003250
Johan Hedberg1707c602013-03-15 17:07:15 -05003251 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003252 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3253 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003254}
3255
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003256static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3257 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003258{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003259 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003260
Marcel Holtmann181d6952020-05-06 09:57:47 +02003261 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003262
Johan Hedberg1707c602013-03-15 17:07:15 -05003263 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003264 MGMT_OP_USER_PASSKEY_REPLY,
3265 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003266}
3267
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003268static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003269 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003270{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003271 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003272
Marcel Holtmann181d6952020-05-06 09:57:47 +02003273 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003274
Johan Hedberg1707c602013-03-15 17:07:15 -05003275 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3277 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003278}
3279
Brian Gix5e233ed2021-10-27 16:58:57 -07003280static int adv_expire_sync(struct hci_dev *hdev, u32 flags)
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003281{
3282 struct adv_info *adv_instance;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003283
3284 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3285 if (!adv_instance)
Brian Gix5e233ed2021-10-27 16:58:57 -07003286 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003287
3288 /* stop if current instance doesn't need to be changed */
3289 if (!(adv_instance->flags & flags))
Brian Gix5e233ed2021-10-27 16:58:57 -07003290 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003291
3292 cancel_adv_timeout(hdev);
3293
3294 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3295 if (!adv_instance)
Brian Gix5e233ed2021-10-27 16:58:57 -07003296 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003297
Brian Gix5e233ed2021-10-27 16:58:57 -07003298 hci_schedule_adv_instance_sync(hdev, adv_instance->instance, true);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003299
Brian Gix5e233ed2021-10-27 16:58:57 -07003300 return 0;
3301}
3302
3303static int name_changed_sync(struct hci_dev *hdev, void *data)
3304{
3305 return adv_expire_sync(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003306}
3307
Brian Gix6f6ff382021-10-27 16:58:54 -07003308static void set_name_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg13928972013-03-15 17:07:00 -05003309{
Brian Gix6f6ff382021-10-27 16:58:54 -07003310 struct mgmt_pending_cmd *cmd = data;
3311 struct mgmt_cp_set_local_name *cp = cmd->param;
3312 u8 status = mgmt_status(err);
Johan Hedberg13928972013-03-15 17:07:00 -05003313
Brian Gix6f6ff382021-10-27 16:58:54 -07003314 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg13928972013-03-15 17:07:00 -05003315
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003316 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003317 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Brian Gix6f6ff382021-10-27 16:58:54 -07003318 status);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003319 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003320 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3321 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003322
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003323 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Brian Gix5e233ed2021-10-27 16:58:57 -07003324 hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003325 }
3326
Johan Hedberg13928972013-03-15 17:07:00 -05003327 mgmt_pending_remove(cmd);
Brian Gix6f6ff382021-10-27 16:58:54 -07003328}
Johan Hedberg13928972013-03-15 17:07:00 -05003329
Brian Gix6f6ff382021-10-27 16:58:54 -07003330static int set_name_sync(struct hci_dev *hdev, void *data)
3331{
3332 if (lmp_bredr_capable(hdev)) {
3333 hci_update_name_sync(hdev);
3334 hci_update_eir_sync(hdev);
3335 }
3336
3337 /* The name is stored in the scan response data and so
3338 * no need to update the advertising data here.
3339 */
3340 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
3341 hci_update_scan_rsp_data_sync(hdev, hdev->cur_adv_instance);
3342
3343 return 0;
Johan Hedberg13928972013-03-15 17:07:00 -05003344}
3345
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003346static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003347 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003348{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003349 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003350 struct mgmt_pending_cmd *cmd;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003351 int err;
3352
Marcel Holtmann181d6952020-05-06 09:57:47 +02003353 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003354
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003355 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003356
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003357 /* If the old values are the same as the new ones just return a
3358 * direct command complete event.
3359 */
3360 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3361 !memcmp(hdev->short_name, cp->short_name,
3362 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003363 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3364 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003365 goto failed;
3366 }
3367
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003368 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003369
Johan Hedbergb5235a62012-02-21 14:32:24 +02003370 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003371 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003372
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003373 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3374 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003375 if (err < 0)
3376 goto failed;
3377
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003378 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3379 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003380 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003381
Johan Hedbergb5235a62012-02-21 14:32:24 +02003382 goto failed;
3383 }
3384
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003385 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Brian Gix6f6ff382021-10-27 16:58:54 -07003386 if (!cmd)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003387 err = -ENOMEM;
Brian Gix6f6ff382021-10-27 16:58:54 -07003388 else
3389 err = hci_cmd_sync_queue(hdev, set_name_sync, cmd,
3390 set_name_complete);
3391
3392 if (err < 0) {
3393 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3394 MGMT_STATUS_FAILED);
3395
3396 if (cmd)
3397 mgmt_pending_remove(cmd);
3398
Johan Hedbergb312b1612011-03-16 14:29:37 +02003399 goto failed;
3400 }
3401
Johan Hedberg13928972013-03-15 17:07:00 -05003402 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3403
Johan Hedbergb312b1612011-03-16 14:29:37 +02003404failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003405 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003406 return err;
3407}
3408
Brian Gix5e233ed2021-10-27 16:58:57 -07003409static int appearance_changed_sync(struct hci_dev *hdev, void *data)
3410{
3411 return adv_expire_sync(hdev, MGMT_ADV_FLAG_APPEARANCE);
3412}
3413
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003414static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3415 u16 len)
3416{
3417 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003418 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003419 int err;
3420
Marcel Holtmann181d6952020-05-06 09:57:47 +02003421 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003422
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003423 if (!lmp_le_capable(hdev))
3424 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3425 MGMT_STATUS_NOT_SUPPORTED);
3426
Alain Michaud6613bab2020-01-22 19:47:44 +00003427 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003428
3429 hci_dev_lock(hdev);
3430
Alain Michaud6613bab2020-01-22 19:47:44 +00003431 if (hdev->appearance != appearance) {
3432 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003433
3434 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Brian Gix5e233ed2021-10-27 16:58:57 -07003435 hci_cmd_sync_queue(hdev, appearance_changed_sync, NULL,
3436 NULL);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003437
3438 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003439 }
3440
3441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3442 0);
3443
3444 hci_dev_unlock(hdev);
3445
3446 return err;
3447}
3448
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303449static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3450 void *data, u16 len)
3451{
Reo Shiseki353021582020-11-19 16:37:11 +09003452 struct mgmt_rp_get_phy_configuration rp;
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303453
Marcel Holtmann181d6952020-05-06 09:57:47 +02003454 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303455
3456 hci_dev_lock(hdev);
3457
3458 memset(&rp, 0, sizeof(rp));
3459
3460 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3461 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3462 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3463
3464 hci_dev_unlock(hdev);
3465
3466 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3467 &rp, sizeof(rp));
3468}
3469
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303470int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3471{
3472 struct mgmt_ev_phy_configuration_changed ev;
3473
3474 memset(&ev, 0, sizeof(ev));
3475
3476 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3477
3478 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3479 sizeof(ev), skip);
3480}
3481
Brian Gix71efbb02021-10-27 16:58:55 -07003482static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303483{
Brian Gix71efbb02021-10-27 16:58:55 -07003484 struct mgmt_pending_cmd *cmd = data;
3485 struct sk_buff *skb = cmd->skb;
3486 u8 status = mgmt_status(err);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303487
Brian Gix71efbb02021-10-27 16:58:55 -07003488 if (!status) {
3489 if (!skb)
3490 status = MGMT_STATUS_FAILED;
3491 else if (IS_ERR(skb))
3492 status = mgmt_status(PTR_ERR(skb));
3493 else
3494 status = mgmt_status(skb->data[0]);
3495 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303496
Brian Gix71efbb02021-10-27 16:58:55 -07003497 bt_dev_dbg(hdev, "status %d", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303498
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303499 if (status) {
3500 mgmt_cmd_status(cmd->sk, hdev->id,
Brian Gix71efbb02021-10-27 16:58:55 -07003501 MGMT_OP_SET_PHY_CONFIGURATION, status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303502 } else {
3503 mgmt_cmd_complete(cmd->sk, hdev->id,
3504 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3505 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303506
3507 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303508 }
3509
Brian Gix71efbb02021-10-27 16:58:55 -07003510 if (skb && !IS_ERR(skb))
3511 kfree_skb(skb);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303512
Brian Gix71efbb02021-10-27 16:58:55 -07003513 mgmt_pending_remove(cmd);
3514}
3515
3516static int set_default_phy_sync(struct hci_dev *hdev, void *data)
3517{
3518 struct mgmt_pending_cmd *cmd = data;
3519 struct mgmt_cp_set_phy_configuration *cp = cmd->param;
3520 struct hci_cp_le_set_default_phy cp_phy;
3521 u32 selected_phys = __le32_to_cpu(cp->selected_phys);
3522
3523 memset(&cp_phy, 0, sizeof(cp_phy));
3524
3525 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3526 cp_phy.all_phys |= 0x01;
3527
3528 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3529 cp_phy.all_phys |= 0x02;
3530
3531 if (selected_phys & MGMT_PHY_LE_1M_TX)
3532 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3533
3534 if (selected_phys & MGMT_PHY_LE_2M_TX)
3535 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3536
3537 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3538 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3539
3540 if (selected_phys & MGMT_PHY_LE_1M_RX)
3541 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3542
3543 if (selected_phys & MGMT_PHY_LE_2M_RX)
3544 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3545
3546 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3547 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3548
3549 cmd->skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_DEFAULT_PHY,
3550 sizeof(cp_phy), &cp_phy, HCI_CMD_TIMEOUT);
3551
3552 return 0;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303553}
3554
3555static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3556 void *data, u16 len)
3557{
Reo Shiseki353021582020-11-19 16:37:11 +09003558 struct mgmt_cp_set_phy_configuration *cp = data;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303559 struct mgmt_pending_cmd *cmd;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303560 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3561 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303562 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303563 int err;
3564
Marcel Holtmann181d6952020-05-06 09:57:47 +02003565 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303566
3567 configurable_phys = get_configurable_phys(hdev);
3568 supported_phys = get_supported_phys(hdev);
3569 selected_phys = __le32_to_cpu(cp->selected_phys);
3570
3571 if (selected_phys & ~supported_phys)
3572 return mgmt_cmd_status(sk, hdev->id,
3573 MGMT_OP_SET_PHY_CONFIGURATION,
3574 MGMT_STATUS_INVALID_PARAMS);
3575
3576 unconfigure_phys = supported_phys & ~configurable_phys;
3577
3578 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3579 return mgmt_cmd_status(sk, hdev->id,
3580 MGMT_OP_SET_PHY_CONFIGURATION,
3581 MGMT_STATUS_INVALID_PARAMS);
3582
3583 if (selected_phys == get_selected_phys(hdev))
3584 return mgmt_cmd_complete(sk, hdev->id,
3585 MGMT_OP_SET_PHY_CONFIGURATION,
3586 0, NULL, 0);
3587
3588 hci_dev_lock(hdev);
3589
3590 if (!hdev_is_powered(hdev)) {
3591 err = mgmt_cmd_status(sk, hdev->id,
3592 MGMT_OP_SET_PHY_CONFIGURATION,
3593 MGMT_STATUS_REJECTED);
3594 goto unlock;
3595 }
3596
3597 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3598 err = mgmt_cmd_status(sk, hdev->id,
3599 MGMT_OP_SET_PHY_CONFIGURATION,
3600 MGMT_STATUS_BUSY);
3601 goto unlock;
3602 }
3603
3604 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3605 pkt_type |= (HCI_DH3 | HCI_DM3);
3606 else
3607 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3608
3609 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3610 pkt_type |= (HCI_DH5 | HCI_DM5);
3611 else
3612 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3613
3614 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3615 pkt_type &= ~HCI_2DH1;
3616 else
3617 pkt_type |= HCI_2DH1;
3618
3619 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3620 pkt_type &= ~HCI_2DH3;
3621 else
3622 pkt_type |= HCI_2DH3;
3623
3624 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3625 pkt_type &= ~HCI_2DH5;
3626 else
3627 pkt_type |= HCI_2DH5;
3628
3629 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3630 pkt_type &= ~HCI_3DH1;
3631 else
3632 pkt_type |= HCI_3DH1;
3633
3634 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3635 pkt_type &= ~HCI_3DH3;
3636 else
3637 pkt_type |= HCI_3DH3;
3638
3639 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3640 pkt_type &= ~HCI_3DH5;
3641 else
3642 pkt_type |= HCI_3DH5;
3643
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303644 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303645 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303646 changed = true;
3647 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303648
3649 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3650 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303651 if (changed)
3652 mgmt_phy_configuration_changed(hdev, sk);
3653
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303654 err = mgmt_cmd_complete(sk, hdev->id,
3655 MGMT_OP_SET_PHY_CONFIGURATION,
3656 0, NULL, 0);
3657
3658 goto unlock;
3659 }
3660
3661 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3662 len);
Brian Gix71efbb02021-10-27 16:58:55 -07003663 if (!cmd)
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303664 err = -ENOMEM;
Brian Gix71efbb02021-10-27 16:58:55 -07003665 else
3666 err = hci_cmd_sync_queue(hdev, set_default_phy_sync, cmd,
3667 set_default_phy_complete);
3668
3669 if (err < 0) {
3670 err = mgmt_cmd_status(sk, hdev->id,
3671 MGMT_OP_SET_PHY_CONFIGURATION,
3672 MGMT_STATUS_FAILED);
3673
3674 if (cmd)
3675 mgmt_pending_remove(cmd);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303676 }
3677
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303678unlock:
3679 hci_dev_unlock(hdev);
3680
3681 return err;
3682}
3683
Alain Michaud600a8742020-01-07 00:43:17 +00003684static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3685 u16 len)
3686{
3687 int err = MGMT_STATUS_SUCCESS;
3688 struct mgmt_cp_set_blocked_keys *keys = data;
3689 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3690 sizeof(struct mgmt_blocked_key_info));
3691 u16 key_count, expected_len;
3692 int i;
3693
Marcel Holtmann181d6952020-05-06 09:57:47 +02003694 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003695
3696 key_count = __le16_to_cpu(keys->key_count);
3697 if (key_count > max_key_count) {
3698 bt_dev_err(hdev, "too big key_count value %u", key_count);
3699 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3700 MGMT_STATUS_INVALID_PARAMS);
3701 }
3702
3703 expected_len = struct_size(keys, keys, key_count);
3704 if (expected_len != len) {
3705 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3706 expected_len, len);
3707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3708 MGMT_STATUS_INVALID_PARAMS);
3709 }
3710
3711 hci_dev_lock(hdev);
3712
3713 hci_blocked_keys_clear(hdev);
3714
3715 for (i = 0; i < keys->key_count; ++i) {
3716 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3717
3718 if (!b) {
3719 err = MGMT_STATUS_NO_RESOURCES;
3720 break;
3721 }
3722
3723 b->type = keys->keys[i].type;
3724 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3725 list_add_rcu(&b->list, &hdev->blocked_keys);
3726 }
3727 hci_dev_unlock(hdev);
3728
3729 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3730 err, NULL, 0);
3731}
3732
Alain Michaud00bce3f2020-03-05 16:14:59 +00003733static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3734 void *data, u16 len)
3735{
3736 struct mgmt_mode *cp = data;
3737 int err;
3738 bool changed = false;
3739
Marcel Holtmann181d6952020-05-06 09:57:47 +02003740 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003741
3742 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3743 return mgmt_cmd_status(sk, hdev->id,
3744 MGMT_OP_SET_WIDEBAND_SPEECH,
3745 MGMT_STATUS_NOT_SUPPORTED);
3746
3747 if (cp->val != 0x00 && cp->val != 0x01)
3748 return mgmt_cmd_status(sk, hdev->id,
3749 MGMT_OP_SET_WIDEBAND_SPEECH,
3750 MGMT_STATUS_INVALID_PARAMS);
3751
3752 hci_dev_lock(hdev);
3753
3754 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3755 err = mgmt_cmd_status(sk, hdev->id,
3756 MGMT_OP_SET_WIDEBAND_SPEECH,
3757 MGMT_STATUS_BUSY);
3758 goto unlock;
3759 }
3760
3761 if (hdev_is_powered(hdev) &&
3762 !!cp->val != hci_dev_test_flag(hdev,
3763 HCI_WIDEBAND_SPEECH_ENABLED)) {
3764 err = mgmt_cmd_status(sk, hdev->id,
3765 MGMT_OP_SET_WIDEBAND_SPEECH,
3766 MGMT_STATUS_REJECTED);
3767 goto unlock;
3768 }
3769
3770 if (cp->val)
3771 changed = !hci_dev_test_and_set_flag(hdev,
3772 HCI_WIDEBAND_SPEECH_ENABLED);
3773 else
3774 changed = hci_dev_test_and_clear_flag(hdev,
3775 HCI_WIDEBAND_SPEECH_ENABLED);
3776
3777 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3778 if (err < 0)
3779 goto unlock;
3780
3781 if (changed)
3782 err = new_settings(hdev, sk);
3783
3784unlock:
3785 hci_dev_unlock(hdev);
3786 return err;
3787}
3788
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003789static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
3790 void *data, u16 data_len)
Marcel Holtmannbc292252020-04-03 21:44:05 +02003791{
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003792 char buf[20];
3793 struct mgmt_rp_read_controller_cap *rp = (void *)buf;
3794 u16 cap_len = 0;
Marcel Holtmannbc292252020-04-03 21:44:05 +02003795 u8 flags = 0;
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003796 u8 tx_power_range[2];
Marcel Holtmannbc292252020-04-03 21:44:05 +02003797
3798 bt_dev_dbg(hdev, "sock %p", sk);
3799
3800 memset(&buf, 0, sizeof(buf));
3801
3802 hci_dev_lock(hdev);
3803
3804 /* When the Read Simple Pairing Options command is supported, then
3805 * the remote public key validation is supported.
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003806 *
3807 * Alternatively, when Microsoft extensions are available, they can
3808 * indicate support for public key validation as well.
Marcel Holtmannbc292252020-04-03 21:44:05 +02003809 */
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003810 if ((hdev->commands[41] & 0x08) || msft_curve_validity(hdev))
Marcel Holtmannbc292252020-04-03 21:44:05 +02003811 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3812
3813 flags |= 0x02; /* Remote public key validation (LE) */
3814
3815 /* When the Read Encryption Key Size command is supported, then the
3816 * encryption key size is enforced.
3817 */
3818 if (hdev->commands[20] & 0x10)
3819 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3820
3821 flags |= 0x08; /* Encryption key size enforcement (LE) */
3822
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003823 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS,
3824 &flags, 1);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003825
3826 /* When the Read Simple Pairing Options command is supported, then
3827 * also max encryption key size information is provided.
3828 */
3829 if (hdev->commands[41] & 0x08)
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003830 cap_len = eir_append_le16(rp->cap, cap_len,
3831 MGMT_CAP_MAX_ENC_KEY_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02003832 hdev->max_enc_key_size);
3833
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003834 cap_len = eir_append_le16(rp->cap, cap_len,
3835 MGMT_CAP_SMP_MAX_ENC_KEY_SIZE,
3836 SMP_MAX_ENC_KEY_SIZE);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003837
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003838 /* Append the min/max LE tx power parameters if we were able to fetch
3839 * it from the controller
3840 */
3841 if (hdev->commands[38] & 0x80) {
3842 memcpy(&tx_power_range[0], &hdev->min_le_tx_power, 1);
3843 memcpy(&tx_power_range[1], &hdev->max_le_tx_power, 1);
3844 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR,
3845 tx_power_range, 2);
3846 }
3847
3848 rp->cap_len = cpu_to_le16(cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003849
3850 hci_dev_unlock(hdev);
3851
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003852 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0,
3853 rp, sizeof(*rp) + cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003854}
3855
Marcel Holtmanne625e502020-05-06 09:57:52 +02003856#ifdef CONFIG_BT_FEATURE_DEBUG
3857/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3858static const u8 debug_uuid[16] = {
3859 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3860 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3861};
3862#endif
3863
Joseph Hwangae7d9252021-08-15 20:17:16 +08003864/* 330859bc-7506-492d-9370-9a6f0614037f */
3865static const u8 quality_report_uuid[16] = {
3866 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
3867 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
3868};
3869
Kiran Kad933152021-09-07 15:42:47 +05303870/* a6695ace-ee7f-4fb9-881a-5fac66c629af */
3871static const u8 offload_codecs_uuid[16] = {
3872 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88,
3873 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6,
3874};
3875
Alain Michaud15d8ce02020-07-07 17:46:06 +02003876/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3877static const u8 simult_central_periph_uuid[16] = {
3878 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3879 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3880};
3881
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303882/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3883static const u8 rpa_resolution_uuid[16] = {
3884 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3885 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3886};
3887
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003888static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3889 void *data, u16 data_len)
3890{
Kiran Kad933152021-09-07 15:42:47 +05303891 char buf[102]; /* Enough space for 5 features: 2 + 20 * 5 */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003892 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3893 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003894 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003895
3896 bt_dev_dbg(hdev, "sock %p", sk);
3897
3898 memset(&buf, 0, sizeof(buf));
3899
Marcel Holtmanne625e502020-05-06 09:57:52 +02003900#ifdef CONFIG_BT_FEATURE_DEBUG
3901 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003902 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003903
3904 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3905 rp->features[idx].flags = cpu_to_le32(flags);
3906 idx++;
3907 }
3908#endif
3909
Alain Michaud15d8ce02020-07-07 17:46:06 +02003910 if (hdev) {
3911 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3912 (hdev->le_states[4] & 0x08) && /* Central */
3913 (hdev->le_states[4] & 0x40) && /* Peripheral */
3914 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3915 flags = BIT(0);
3916 else
3917 flags = 0;
3918
3919 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3920 rp->features[idx].flags = cpu_to_le32(flags);
3921 idx++;
3922 }
3923
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07003924 if (hdev && ll_privacy_capable(hdev)) {
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303925 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3926 flags = BIT(0) | BIT(1);
3927 else
3928 flags = BIT(1);
3929
3930 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3931 rp->features[idx].flags = cpu_to_le32(flags);
3932 idx++;
3933 }
3934
Joseph Hwang258f56d2021-11-02 15:19:29 +08003935 if (hdev && (aosp_has_quality_report(hdev) ||
3936 hdev->set_quality_report)) {
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003937 if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
Joseph Hwangae7d9252021-08-15 20:17:16 +08003938 flags = BIT(0);
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003939 else
Joseph Hwangae7d9252021-08-15 20:17:16 +08003940 flags = 0;
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003941
Joseph Hwangae7d9252021-08-15 20:17:16 +08003942 memcpy(rp->features[idx].uuid, quality_report_uuid, 16);
3943 rp->features[idx].flags = cpu_to_le32(flags);
3944 idx++;
3945 }
3946
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003947 if (hdev && hdev->get_data_path_id) {
3948 if (hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED))
Kiran Kad933152021-09-07 15:42:47 +05303949 flags = BIT(0);
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003950 else
Kiran Kad933152021-09-07 15:42:47 +05303951 flags = 0;
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003952
Kiran Kad933152021-09-07 15:42:47 +05303953 memcpy(rp->features[idx].uuid, offload_codecs_uuid, 16);
3954 rp->features[idx].flags = cpu_to_le32(flags);
3955 idx++;
3956 }
3957
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003958 rp->feature_count = cpu_to_le16(idx);
3959
3960 /* After reading the experimental features information, enable
3961 * the events to update client on any future change.
3962 */
3963 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3964
3965 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3966 MGMT_OP_READ_EXP_FEATURES_INFO,
3967 0, rp, sizeof(*rp) + (20 * idx));
3968}
3969
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303970static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3971 struct sock *skip)
3972{
3973 struct mgmt_ev_exp_feature_changed ev;
3974
3975 memset(&ev, 0, sizeof(ev));
3976 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3977 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3978
3979 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3980 &ev, sizeof(ev),
3981 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3982
3983}
3984
Marcel Holtmanne625e502020-05-06 09:57:52 +02003985#ifdef CONFIG_BT_FEATURE_DEBUG
3986static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3987{
3988 struct mgmt_ev_exp_feature_changed ev;
3989
3990 memset(&ev, 0, sizeof(ev));
3991 memcpy(ev.uuid, debug_uuid, 16);
3992 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3993
3994 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3995 &ev, sizeof(ev),
3996 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3997}
3998#endif
3999
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004000static int exp_quality_report_feature_changed(bool enabled,
4001 struct hci_dev *hdev,
4002 struct sock *skip)
Joseph Hwangae7d9252021-08-15 20:17:16 +08004003{
4004 struct mgmt_ev_exp_feature_changed ev;
4005
4006 memset(&ev, 0, sizeof(ev));
4007 memcpy(ev.uuid, quality_report_uuid, 16);
4008 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4009
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004010 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
Joseph Hwangae7d9252021-08-15 20:17:16 +08004011 &ev, sizeof(ev),
4012 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4013}
4014
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004015#define EXP_FEAT(_uuid, _set_func) \
4016{ \
4017 .uuid = _uuid, \
4018 .set_func = _set_func, \
4019}
4020
4021/* The zero key uuid is special. Multiple exp features are set through it. */
4022static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
4023 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
4024{
4025 struct mgmt_rp_set_exp_feature rp;
4026
4027 memset(rp.uuid, 0, 16);
4028 rp.flags = cpu_to_le32(0);
4029
4030#ifdef CONFIG_BT_FEATURE_DEBUG
4031 if (!hdev) {
4032 bool changed = bt_dbg_get();
4033
4034 bt_dbg_set(false);
4035
4036 if (changed)
4037 exp_debug_feature_changed(false, sk);
4038 }
4039#endif
4040
4041 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
4042 bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4043
4044 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4045
4046 if (changed)
4047 exp_ll_privacy_feature_changed(false, hdev, sk);
4048 }
4049
4050 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4051
4052 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4053 MGMT_OP_SET_EXP_FEATURE, 0,
4054 &rp, sizeof(rp));
4055}
4056
4057#ifdef CONFIG_BT_FEATURE_DEBUG
4058static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
4059 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
4060{
4061 struct mgmt_rp_set_exp_feature rp;
4062
4063 bool val, changed;
4064 int err;
4065
4066 /* Command requires to use the non-controller index */
4067 if (hdev)
4068 return mgmt_cmd_status(sk, hdev->id,
4069 MGMT_OP_SET_EXP_FEATURE,
4070 MGMT_STATUS_INVALID_INDEX);
4071
4072 /* Parameters are limited to a single octet */
4073 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4074 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4075 MGMT_OP_SET_EXP_FEATURE,
4076 MGMT_STATUS_INVALID_PARAMS);
4077
4078 /* Only boolean on/off is supported */
4079 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4080 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4081 MGMT_OP_SET_EXP_FEATURE,
4082 MGMT_STATUS_INVALID_PARAMS);
4083
4084 val = !!cp->param[0];
4085 changed = val ? !bt_dbg_get() : bt_dbg_get();
4086 bt_dbg_set(val);
4087
4088 memcpy(rp.uuid, debug_uuid, 16);
4089 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4090
4091 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4092
4093 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
4094 MGMT_OP_SET_EXP_FEATURE, 0,
4095 &rp, sizeof(rp));
4096
4097 if (changed)
4098 exp_debug_feature_changed(val, sk);
4099
4100 return err;
4101}
4102#endif
4103
4104static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
4105 struct mgmt_cp_set_exp_feature *cp,
4106 u16 data_len)
4107{
4108 struct mgmt_rp_set_exp_feature rp;
4109 bool val, changed;
4110 int err;
4111 u32 flags;
4112
4113 /* Command requires to use the controller index */
4114 if (!hdev)
4115 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4116 MGMT_OP_SET_EXP_FEATURE,
4117 MGMT_STATUS_INVALID_INDEX);
4118
4119 /* Changes can only be made when controller is powered down */
4120 if (hdev_is_powered(hdev))
4121 return mgmt_cmd_status(sk, hdev->id,
4122 MGMT_OP_SET_EXP_FEATURE,
4123 MGMT_STATUS_REJECTED);
4124
4125 /* Parameters are limited to a single octet */
4126 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4127 return mgmt_cmd_status(sk, hdev->id,
4128 MGMT_OP_SET_EXP_FEATURE,
4129 MGMT_STATUS_INVALID_PARAMS);
4130
4131 /* Only boolean on/off is supported */
4132 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4133 return mgmt_cmd_status(sk, hdev->id,
4134 MGMT_OP_SET_EXP_FEATURE,
4135 MGMT_STATUS_INVALID_PARAMS);
4136
4137 val = !!cp->param[0];
4138
4139 if (val) {
4140 changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4141 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4142 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
4143
4144 /* Enable LL privacy + supported settings changed */
4145 flags = BIT(0) | BIT(1);
4146 } else {
4147 changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4148 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4149
4150 /* Disable LL privacy + supported settings changed */
4151 flags = BIT(1);
4152 }
4153
4154 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4155 rp.flags = cpu_to_le32(flags);
4156
4157 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4158
4159 err = mgmt_cmd_complete(sk, hdev->id,
4160 MGMT_OP_SET_EXP_FEATURE, 0,
4161 &rp, sizeof(rp));
4162
4163 if (changed)
4164 exp_ll_privacy_feature_changed(val, hdev, sk);
4165
4166 return err;
4167}
4168
Joseph Hwangae7d9252021-08-15 20:17:16 +08004169static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
4170 struct mgmt_cp_set_exp_feature *cp,
4171 u16 data_len)
4172{
4173 struct mgmt_rp_set_exp_feature rp;
4174 bool val, changed;
4175 int err;
4176
4177 /* Command requires to use a valid controller index */
4178 if (!hdev)
4179 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4180 MGMT_OP_SET_EXP_FEATURE,
4181 MGMT_STATUS_INVALID_INDEX);
4182
4183 /* Parameters are limited to a single octet */
4184 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4185 return mgmt_cmd_status(sk, hdev->id,
4186 MGMT_OP_SET_EXP_FEATURE,
4187 MGMT_STATUS_INVALID_PARAMS);
4188
4189 /* Only boolean on/off is supported */
4190 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4191 return mgmt_cmd_status(sk, hdev->id,
4192 MGMT_OP_SET_EXP_FEATURE,
4193 MGMT_STATUS_INVALID_PARAMS);
4194
4195 hci_req_sync_lock(hdev);
4196
4197 val = !!cp->param[0];
4198 changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
4199
Joseph Hwang258f56d2021-11-02 15:19:29 +08004200 if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) {
Joseph Hwangae7d9252021-08-15 20:17:16 +08004201 err = mgmt_cmd_status(sk, hdev->id,
4202 MGMT_OP_SET_EXP_FEATURE,
4203 MGMT_STATUS_NOT_SUPPORTED);
4204 goto unlock_quality_report;
4205 }
4206
4207 if (changed) {
Joseph Hwang258f56d2021-11-02 15:19:29 +08004208 if (hdev->set_quality_report)
4209 err = hdev->set_quality_report(hdev, val);
4210 else
4211 err = aosp_set_quality_report(hdev, val);
4212
Joseph Hwangae7d9252021-08-15 20:17:16 +08004213 if (err) {
4214 err = mgmt_cmd_status(sk, hdev->id,
4215 MGMT_OP_SET_EXP_FEATURE,
4216 MGMT_STATUS_FAILED);
4217 goto unlock_quality_report;
4218 }
Joseph Hwang258f56d2021-11-02 15:19:29 +08004219
Joseph Hwangae7d9252021-08-15 20:17:16 +08004220 if (val)
4221 hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
4222 else
4223 hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
4224 }
4225
4226 bt_dev_dbg(hdev, "quality report enable %d changed %d", val, changed);
4227
4228 memcpy(rp.uuid, quality_report_uuid, 16);
4229 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4230 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
Joseph Hwang258f56d2021-11-02 15:19:29 +08004231
4232 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0,
Joseph Hwangae7d9252021-08-15 20:17:16 +08004233 &rp, sizeof(rp));
4234
4235 if (changed)
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004236 exp_quality_report_feature_changed(val, hdev, sk);
Joseph Hwangae7d9252021-08-15 20:17:16 +08004237
4238unlock_quality_report:
4239 hci_req_sync_unlock(hdev);
4240 return err;
4241}
4242
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004243static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
4244 struct sock *skip)
Kiran Kad933152021-09-07 15:42:47 +05304245{
4246 struct mgmt_ev_exp_feature_changed ev;
4247
4248 memset(&ev, 0, sizeof(ev));
4249 memcpy(ev.uuid, offload_codecs_uuid, 16);
4250 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4251
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004252 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
Kiran Kad933152021-09-07 15:42:47 +05304253 &ev, sizeof(ev),
4254 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4255}
4256
4257static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
4258 struct mgmt_cp_set_exp_feature *cp,
4259 u16 data_len)
4260{
4261 bool val, changed;
4262 int err;
4263 struct mgmt_rp_set_exp_feature rp;
4264
4265 /* Command requires to use a valid controller index */
4266 if (!hdev)
4267 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4268 MGMT_OP_SET_EXP_FEATURE,
4269 MGMT_STATUS_INVALID_INDEX);
4270
4271 /* Parameters are limited to a single octet */
4272 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4273 return mgmt_cmd_status(sk, hdev->id,
4274 MGMT_OP_SET_EXP_FEATURE,
4275 MGMT_STATUS_INVALID_PARAMS);
4276
4277 /* Only boolean on/off is supported */
4278 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4279 return mgmt_cmd_status(sk, hdev->id,
4280 MGMT_OP_SET_EXP_FEATURE,
4281 MGMT_STATUS_INVALID_PARAMS);
4282
4283 val = !!cp->param[0];
4284 changed = (val != hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED));
4285
4286 if (!hdev->get_data_path_id) {
4287 return mgmt_cmd_status(sk, hdev->id,
4288 MGMT_OP_SET_EXP_FEATURE,
4289 MGMT_STATUS_NOT_SUPPORTED);
4290 }
4291
4292 if (changed) {
4293 if (val)
4294 hci_dev_set_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4295 else
4296 hci_dev_clear_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4297 }
4298
4299 bt_dev_info(hdev, "offload codecs enable %d changed %d",
4300 val, changed);
4301
4302 memcpy(rp.uuid, offload_codecs_uuid, 16);
4303 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4304 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4305 err = mgmt_cmd_complete(sk, hdev->id,
4306 MGMT_OP_SET_EXP_FEATURE, 0,
4307 &rp, sizeof(rp));
4308
4309 if (changed)
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004310 exp_offload_codec_feature_changed(val, hdev, sk);
Kiran Kad933152021-09-07 15:42:47 +05304311
4312 return err;
4313}
4314
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004315static const struct mgmt_exp_feature {
4316 const u8 *uuid;
4317 int (*set_func)(struct sock *sk, struct hci_dev *hdev,
4318 struct mgmt_cp_set_exp_feature *cp, u16 data_len);
4319} exp_features[] = {
4320 EXP_FEAT(ZERO_KEY, set_zero_key_func),
4321#ifdef CONFIG_BT_FEATURE_DEBUG
4322 EXP_FEAT(debug_uuid, set_debug_func),
4323#endif
4324 EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
Joseph Hwangae7d9252021-08-15 20:17:16 +08004325 EXP_FEAT(quality_report_uuid, set_quality_report_func),
Kiran Kad933152021-09-07 15:42:47 +05304326 EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004327
4328 /* end with a null feature */
4329 EXP_FEAT(NULL, NULL)
4330};
4331
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004332static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
4333 void *data, u16 data_len)
4334{
4335 struct mgmt_cp_set_exp_feature *cp = data;
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004336 size_t i = 0;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004337
4338 bt_dev_dbg(hdev, "sock %p", sk);
4339
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004340 for (i = 0; exp_features[i].uuid; i++) {
4341 if (!memcmp(cp->uuid, exp_features[i].uuid, 16))
4342 return exp_features[i].set_func(sk, hdev, cp, data_len);
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05304343 }
4344
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004345 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4346 MGMT_OP_SET_EXP_FEATURE,
4347 MGMT_STATUS_NOT_SUPPORTED);
4348}
4349
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004350#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4351
4352static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4353 u16 data_len)
4354{
4355 struct mgmt_cp_get_device_flags *cp = data;
4356 struct mgmt_rp_get_device_flags rp;
4357 struct bdaddr_list_with_flags *br_params;
4358 struct hci_conn_params *params;
4359 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4360 u32 current_flags = 0;
4361 u8 status = MGMT_STATUS_INVALID_PARAMS;
4362
4363 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4364 &cp->addr.bdaddr, cp->addr.type);
4365
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004366 hci_dev_lock(hdev);
4367
Tedd Ho-Jeong An02ce2c22021-05-26 10:36:22 -07004368 memset(&rp, 0, sizeof(rp));
4369
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004370 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004371 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004372 &cp->addr.bdaddr,
4373 cp->addr.type);
4374 if (!br_params)
4375 goto done;
4376
4377 current_flags = br_params->current_flags;
4378 } else {
4379 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4380 le_addr_type(cp->addr.type));
4381
4382 if (!params)
4383 goto done;
4384
4385 current_flags = params->current_flags;
4386 }
4387
4388 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4389 rp.addr.type = cp->addr.type;
4390 rp.supported_flags = cpu_to_le32(supported_flags);
4391 rp.current_flags = cpu_to_le32(current_flags);
4392
4393 status = MGMT_STATUS_SUCCESS;
4394
4395done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004396 hci_dev_unlock(hdev);
4397
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004398 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4399 &rp, sizeof(rp));
4400}
4401
4402static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4403 bdaddr_t *bdaddr, u8 bdaddr_type,
4404 u32 supported_flags, u32 current_flags)
4405{
4406 struct mgmt_ev_device_flags_changed ev;
4407
4408 bacpy(&ev.addr.bdaddr, bdaddr);
4409 ev.addr.type = bdaddr_type;
4410 ev.supported_flags = cpu_to_le32(supported_flags);
4411 ev.current_flags = cpu_to_le32(current_flags);
4412
4413 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4414}
4415
4416static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4417 u16 len)
4418{
4419 struct mgmt_cp_set_device_flags *cp = data;
4420 struct bdaddr_list_with_flags *br_params;
4421 struct hci_conn_params *params;
4422 u8 status = MGMT_STATUS_INVALID_PARAMS;
4423 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4424 u32 current_flags = __le32_to_cpu(cp->current_flags);
4425
4426 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4427 &cp->addr.bdaddr, cp->addr.type,
4428 __le32_to_cpu(current_flags));
4429
4430 if ((supported_flags | current_flags) != supported_flags) {
4431 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4432 current_flags, supported_flags);
4433 goto done;
4434 }
4435
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004436 hci_dev_lock(hdev);
4437
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004438 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004439 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004440 &cp->addr.bdaddr,
4441 cp->addr.type);
4442
4443 if (br_params) {
4444 br_params->current_flags = current_flags;
4445 status = MGMT_STATUS_SUCCESS;
4446 } else {
4447 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4448 &cp->addr.bdaddr, cp->addr.type);
4449 }
4450 } else {
4451 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4452 le_addr_type(cp->addr.type));
4453 if (params) {
4454 params->current_flags = current_flags;
4455 status = MGMT_STATUS_SUCCESS;
4456 } else {
4457 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4458 &cp->addr.bdaddr,
4459 le_addr_type(cp->addr.type));
4460 }
4461 }
4462
4463done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004464 hci_dev_unlock(hdev);
4465
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004466 if (status == MGMT_STATUS_SUCCESS)
4467 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4468 supported_flags, current_flags);
4469
4470 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4471 &cp->addr, sizeof(cp->addr));
4472}
4473
Miao-chen Choub52729f2020-06-17 16:39:16 +02004474static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4475 u16 handle)
4476{
4477 struct mgmt_ev_adv_monitor_added ev;
4478
4479 ev.monitor_handle = cpu_to_le16(handle);
4480
4481 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4482}
4483
Archie Pusaka66bd0952021-01-22 16:36:13 +08004484void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004485{
Archie Pusaka66bd0952021-01-22 16:36:13 +08004486 struct mgmt_ev_adv_monitor_removed ev;
4487 struct mgmt_pending_cmd *cmd;
4488 struct sock *sk_skip = NULL;
4489 struct mgmt_cp_remove_adv_monitor *cp;
4490
4491 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4492 if (cmd) {
4493 cp = cmd->param;
4494
4495 if (cp->monitor_handle)
4496 sk_skip = cmd->sk;
4497 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004498
4499 ev.monitor_handle = cpu_to_le16(handle);
4500
Archie Pusaka66bd0952021-01-22 16:36:13 +08004501 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004502}
4503
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004504static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4505 void *data, u16 len)
4506{
4507 struct adv_monitor *monitor = NULL;
4508 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004509 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004510 size_t rp_size = 0;
4511 __u32 supported = 0;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004512 __u32 enabled = 0;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004513 __u16 num_handles = 0;
4514 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4515
4516 BT_DBG("request for %s", hdev->name);
4517
4518 hci_dev_lock(hdev);
4519
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004520 if (msft_monitor_supported(hdev))
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004521 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4522
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004523 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004524 handles[num_handles++] = monitor->handle;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004525
4526 hci_dev_unlock(hdev);
4527
4528 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4529 rp = kmalloc(rp_size, GFP_KERNEL);
4530 if (!rp)
4531 return -ENOMEM;
4532
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004533 /* All supported features are currently enabled */
4534 enabled = supported;
4535
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004536 rp->supported_features = cpu_to_le32(supported);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004537 rp->enabled_features = cpu_to_le32(enabled);
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004538 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4539 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4540 rp->num_handles = cpu_to_le16(num_handles);
4541 if (num_handles)
4542 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4543
Peilin Yecafd4722020-09-09 03:25:51 -04004544 err = mgmt_cmd_complete(sk, hdev->id,
4545 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4546 MGMT_STATUS_SUCCESS, rp, rp_size);
4547
4548 kfree(rp);
4549
4550 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004551}
4552
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004553int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
Miao-chen Choub1395532020-06-17 16:39:14 +02004554{
Miao-chen Choub1395532020-06-17 16:39:14 +02004555 struct mgmt_rp_add_adv_patterns_monitor rp;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004556 struct mgmt_pending_cmd *cmd;
4557 struct adv_monitor *monitor;
4558 int err = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004559
4560 hci_dev_lock(hdev);
4561
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004562 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4563 if (!cmd) {
4564 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4565 if (!cmd)
4566 goto done;
4567 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004568
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004569 monitor = cmd->user_data;
4570 rp.monitor_handle = cpu_to_le16(monitor->handle);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004571
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004572 if (!status) {
4573 mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4574 hdev->adv_monitors_cnt++;
4575 if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4576 monitor->state = ADV_MONITOR_STATE_REGISTERED;
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004577 hci_update_passive_scan(hdev);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004578 }
4579
4580 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4581 mgmt_status(status), &rp, sizeof(rp));
4582 mgmt_pending_remove(cmd);
4583
4584done:
4585 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004586 bt_dev_dbg(hdev, "add monitor %d complete, status %u",
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004587 rp.monitor_handle, status);
4588
4589 return err;
4590}
4591
4592static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4593 struct adv_monitor *m, u8 status,
4594 void *data, u16 len, u16 op)
4595{
4596 struct mgmt_rp_add_adv_patterns_monitor rp;
4597 struct mgmt_pending_cmd *cmd;
4598 int err;
4599 bool pending;
4600
4601 hci_dev_lock(hdev);
4602
4603 if (status)
4604 goto unlock;
4605
4606 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4607 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4608 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4609 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4610 status = MGMT_STATUS_BUSY;
Miao-chen Choub1395532020-06-17 16:39:14 +02004611 goto unlock;
4612 }
4613
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004614 cmd = mgmt_pending_add(sk, op, hdev, data, len);
4615 if (!cmd) {
4616 status = MGMT_STATUS_NO_RESOURCES;
4617 goto unlock;
4618 }
4619
Howard Chungb1810fe2021-02-03 15:09:29 +08004620 cmd->user_data = m;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004621 pending = hci_add_adv_monitor(hdev, m, &err);
4622 if (err) {
4623 if (err == -ENOSPC || err == -ENOMEM)
4624 status = MGMT_STATUS_NO_RESOURCES;
4625 else if (err == -EINVAL)
4626 status = MGMT_STATUS_INVALID_PARAMS;
4627 else
4628 status = MGMT_STATUS_FAILED;
4629
4630 mgmt_pending_remove(cmd);
4631 goto unlock;
4632 }
4633
4634 if (!pending) {
4635 mgmt_pending_remove(cmd);
4636 rp.monitor_handle = cpu_to_le16(m->handle);
Miao-chen Choub52729f2020-06-17 16:39:16 +02004637 mgmt_adv_monitor_added(sk, hdev, m->handle);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004638 m->state = ADV_MONITOR_STATE_REGISTERED;
4639 hdev->adv_monitors_cnt++;
4640
4641 hci_dev_unlock(hdev);
4642 return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4643 &rp, sizeof(rp));
4644 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004645
Miao-chen Choub1395532020-06-17 16:39:14 +02004646 hci_dev_unlock(hdev);
4647
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004648 return 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004649
4650unlock:
Archie Pusaka66bd0952021-01-22 16:36:13 +08004651 hci_free_adv_monitor(hdev, m);
Miao-chen Choub1395532020-06-17 16:39:14 +02004652 hci_dev_unlock(hdev);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004653 return mgmt_cmd_status(sk, hdev->id, op, status);
4654}
4655
4656static void parse_adv_monitor_rssi(struct adv_monitor *m,
4657 struct mgmt_adv_rssi_thresholds *rssi)
4658{
4659 if (rssi) {
4660 m->rssi.low_threshold = rssi->low_threshold;
4661 m->rssi.low_threshold_timeout =
4662 __le16_to_cpu(rssi->low_threshold_timeout);
4663 m->rssi.high_threshold = rssi->high_threshold;
4664 m->rssi.high_threshold_timeout =
4665 __le16_to_cpu(rssi->high_threshold_timeout);
4666 m->rssi.sampling_period = rssi->sampling_period;
4667 } else {
4668 /* Default values. These numbers are the least constricting
4669 * parameters for MSFT API to work, so it behaves as if there
4670 * are no rssi parameter to consider. May need to be changed
4671 * if other API are to be supported.
4672 */
4673 m->rssi.low_threshold = -127;
4674 m->rssi.low_threshold_timeout = 60;
4675 m->rssi.high_threshold = -127;
4676 m->rssi.high_threshold_timeout = 0;
4677 m->rssi.sampling_period = 0;
4678 }
4679}
4680
4681static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
4682 struct mgmt_adv_pattern *patterns)
4683{
4684 u8 offset = 0, length = 0;
4685 struct adv_pattern *p = NULL;
Archie Pusakab4a221e2021-01-22 16:36:11 +08004686 int i;
4687
4688 for (i = 0; i < pattern_count; i++) {
Archie Pusakab4a221e2021-01-22 16:36:11 +08004689 offset = patterns[i].offset;
4690 length = patterns[i].length;
4691 if (offset >= HCI_MAX_AD_LENGTH ||
4692 length > HCI_MAX_AD_LENGTH ||
4693 (offset + length) > HCI_MAX_AD_LENGTH)
4694 return MGMT_STATUS_INVALID_PARAMS;
4695
4696 p = kmalloc(sizeof(*p), GFP_KERNEL);
4697 if (!p)
4698 return MGMT_STATUS_NO_RESOURCES;
4699
4700 p->ad_type = patterns[i].ad_type;
4701 p->offset = patterns[i].offset;
4702 p->length = patterns[i].length;
4703 memcpy(p->value, patterns[i].value, p->length);
4704
4705 INIT_LIST_HEAD(&p->list);
4706 list_add(&p->list, &m->patterns);
4707 }
4708
Archie Pusakab4a221e2021-01-22 16:36:11 +08004709 return MGMT_STATUS_SUCCESS;
4710}
4711
4712static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4713 void *data, u16 len)
4714{
4715 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4716 struct adv_monitor *m = NULL;
4717 u8 status = MGMT_STATUS_SUCCESS;
4718 size_t expected_size = sizeof(*cp);
4719
4720 BT_DBG("request for %s", hdev->name);
4721
4722 if (len <= sizeof(*cp)) {
4723 status = MGMT_STATUS_INVALID_PARAMS;
4724 goto done;
4725 }
4726
4727 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4728 if (len != expected_size) {
4729 status = MGMT_STATUS_INVALID_PARAMS;
4730 goto done;
4731 }
4732
4733 m = kzalloc(sizeof(*m), GFP_KERNEL);
4734 if (!m) {
4735 status = MGMT_STATUS_NO_RESOURCES;
4736 goto done;
4737 }
4738
4739 INIT_LIST_HEAD(&m->patterns);
4740
4741 parse_adv_monitor_rssi(m, NULL);
4742 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4743
4744done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004745 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004746 MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
4747}
4748
4749static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
4750 void *data, u16 len)
4751{
4752 struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = data;
4753 struct adv_monitor *m = NULL;
4754 u8 status = MGMT_STATUS_SUCCESS;
4755 size_t expected_size = sizeof(*cp);
4756
4757 BT_DBG("request for %s", hdev->name);
4758
4759 if (len <= sizeof(*cp)) {
4760 status = MGMT_STATUS_INVALID_PARAMS;
4761 goto done;
4762 }
4763
4764 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4765 if (len != expected_size) {
4766 status = MGMT_STATUS_INVALID_PARAMS;
4767 goto done;
4768 }
4769
4770 m = kzalloc(sizeof(*m), GFP_KERNEL);
4771 if (!m) {
4772 status = MGMT_STATUS_NO_RESOURCES;
4773 goto done;
4774 }
4775
4776 INIT_LIST_HEAD(&m->patterns);
4777
4778 parse_adv_monitor_rssi(m, &cp->rssi);
4779 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4780
4781done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004782 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004783 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
Miao-chen Choub1395532020-06-17 16:39:14 +02004784}
4785
Archie Pusaka66bd0952021-01-22 16:36:13 +08004786int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4787{
4788 struct mgmt_rp_remove_adv_monitor rp;
4789 struct mgmt_cp_remove_adv_monitor *cp;
4790 struct mgmt_pending_cmd *cmd;
4791 int err = 0;
4792
4793 hci_dev_lock(hdev);
4794
4795 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4796 if (!cmd)
4797 goto done;
4798
4799 cp = cmd->param;
4800 rp.monitor_handle = cp->monitor_handle;
4801
4802 if (!status)
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004803 hci_update_passive_scan(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004804
4805 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4806 mgmt_status(status), &rp, sizeof(rp));
4807 mgmt_pending_remove(cmd);
4808
4809done:
4810 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004811 bt_dev_dbg(hdev, "remove monitor %d complete, status %u",
Archie Pusaka66bd0952021-01-22 16:36:13 +08004812 rp.monitor_handle, status);
4813
4814 return err;
4815}
4816
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004817static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4818 void *data, u16 len)
4819{
4820 struct mgmt_cp_remove_adv_monitor *cp = data;
4821 struct mgmt_rp_remove_adv_monitor rp;
Archie Pusaka66bd0952021-01-22 16:36:13 +08004822 struct mgmt_pending_cmd *cmd;
4823 u16 handle = __le16_to_cpu(cp->monitor_handle);
4824 int err, status;
4825 bool pending;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004826
4827 BT_DBG("request for %s", hdev->name);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004828 rp.monitor_handle = cp->monitor_handle;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004829
4830 hci_dev_lock(hdev);
4831
Archie Pusaka66bd0952021-01-22 16:36:13 +08004832 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4833 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4834 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4835 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4836 status = MGMT_STATUS_BUSY;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004837 goto unlock;
4838 }
4839
Archie Pusaka66bd0952021-01-22 16:36:13 +08004840 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4841 if (!cmd) {
4842 status = MGMT_STATUS_NO_RESOURCES;
4843 goto unlock;
4844 }
4845
4846 if (handle)
4847 pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4848 else
4849 pending = hci_remove_all_adv_monitor(hdev, &err);
4850
4851 if (err) {
4852 mgmt_pending_remove(cmd);
4853
4854 if (err == -ENOENT)
4855 status = MGMT_STATUS_INVALID_INDEX;
4856 else
4857 status = MGMT_STATUS_FAILED;
4858
4859 goto unlock;
4860 }
4861
4862 /* monitor can be removed without forwarding request to controller */
4863 if (!pending) {
4864 mgmt_pending_remove(cmd);
4865 hci_dev_unlock(hdev);
4866
4867 return mgmt_cmd_complete(sk, hdev->id,
4868 MGMT_OP_REMOVE_ADV_MONITOR,
4869 MGMT_STATUS_SUCCESS,
4870 &rp, sizeof(rp));
4871 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004872
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004873 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004874 return 0;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004875
4876unlock:
4877 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004878 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4879 status);
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004880}
4881
Brian Gixf8922442021-10-27 16:58:52 -07004882static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004883{
4884 struct mgmt_rp_read_local_oob_data mgmt_rp;
4885 size_t rp_size = sizeof(mgmt_rp);
Brian Gixf8922442021-10-27 16:58:52 -07004886 struct mgmt_pending_cmd *cmd = data;
4887 struct sk_buff *skb = cmd->skb;
4888 u8 status = mgmt_status(err);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004889
Brian Gixf8922442021-10-27 16:58:52 -07004890 if (!status) {
4891 if (!skb)
4892 status = MGMT_STATUS_FAILED;
4893 else if (IS_ERR(skb))
4894 status = mgmt_status(PTR_ERR(skb));
4895 else
4896 status = mgmt_status(skb->data[0]);
4897 }
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004898
Brian Gixf8922442021-10-27 16:58:52 -07004899 bt_dev_dbg(hdev, "status %d", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004900
Brian Gixf8922442021-10-27 16:58:52 -07004901 if (status) {
4902 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004903 goto remove;
4904 }
4905
4906 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4907
Brian Gixf8922442021-10-27 16:58:52 -07004908 if (!bredr_sc_enabled(hdev)) {
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004909 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4910
4911 if (skb->len < sizeof(*rp)) {
4912 mgmt_cmd_status(cmd->sk, hdev->id,
4913 MGMT_OP_READ_LOCAL_OOB_DATA,
4914 MGMT_STATUS_FAILED);
4915 goto remove;
4916 }
4917
4918 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4919 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4920
4921 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4922 } else {
4923 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4924
4925 if (skb->len < sizeof(*rp)) {
4926 mgmt_cmd_status(cmd->sk, hdev->id,
4927 MGMT_OP_READ_LOCAL_OOB_DATA,
4928 MGMT_STATUS_FAILED);
4929 goto remove;
4930 }
4931
4932 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4933 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4934
4935 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4936 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4937 }
4938
4939 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4940 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4941
4942remove:
Brian Gixf8922442021-10-27 16:58:52 -07004943 if (skb && !IS_ERR(skb))
4944 kfree_skb(skb);
4945
4946 mgmt_pending_free(cmd);
4947}
4948
4949static int read_local_oob_data_sync(struct hci_dev *hdev, void *data)
4950{
4951 struct mgmt_pending_cmd *cmd = data;
4952
4953 if (bredr_sc_enabled(hdev))
4954 cmd->skb = hci_read_local_oob_data_sync(hdev, true, cmd->sk);
4955 else
4956 cmd->skb = hci_read_local_oob_data_sync(hdev, false, cmd->sk);
4957
4958 if (IS_ERR(cmd->skb))
4959 return PTR_ERR(cmd->skb);
4960 else
4961 return 0;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004962}
4963
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004964static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004965 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004966{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004967 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004968 int err;
4969
Marcel Holtmann181d6952020-05-06 09:57:47 +02004970 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004971
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004972 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004973
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004974 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004975 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4976 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004977 goto unlock;
4978 }
4979
Andre Guedes9a1a1992012-07-24 15:03:48 -03004980 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004981 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4982 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004983 goto unlock;
4984 }
4985
Johan Hedberg333ae952015-03-17 13:48:47 +02004986 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004987 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4988 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004989 goto unlock;
4990 }
4991
Brian Gixf8922442021-10-27 16:58:52 -07004992 cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
4993 if (!cmd)
Szymon Jancc35938b2011-03-22 13:12:21 +01004994 err = -ENOMEM;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004995 else
Brian Gixf8922442021-10-27 16:58:52 -07004996 err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
4997 read_local_oob_data_complete);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004998
Brian Gixf8922442021-10-27 16:58:52 -07004999 if (err < 0) {
5000 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5001 MGMT_STATUS_FAILED);
5002
5003 if (cmd)
5004 mgmt_pending_free(cmd);
5005 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005006
5007unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005008 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005009 return err;
5010}
5011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005012static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005013 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01005014{
Johan Hedberg5d57e792015-01-23 10:10:38 +02005015 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01005016 int err;
5017
Marcel Holtmann181d6952020-05-06 09:57:47 +02005018 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01005019
Johan Hedberg5d57e792015-01-23 10:10:38 +02005020 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005021 return mgmt_cmd_complete(sk, hdev->id,
5022 MGMT_OP_ADD_REMOTE_OOB_DATA,
5023 MGMT_STATUS_INVALID_PARAMS,
5024 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02005025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005026 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005027
Marcel Holtmannec109112014-01-10 02:07:30 -08005028 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
5029 struct mgmt_cp_add_remote_oob_data *cp = data;
5030 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005031
Johan Hedbergc19a4952014-11-17 20:52:19 +02005032 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005033 err = mgmt_cmd_complete(sk, hdev->id,
5034 MGMT_OP_ADD_REMOTE_OOB_DATA,
5035 MGMT_STATUS_INVALID_PARAMS,
5036 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02005037 goto unlock;
5038 }
5039
Marcel Holtmannec109112014-01-10 02:07:30 -08005040 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01005041 cp->addr.type, cp->hash,
5042 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08005043 if (err < 0)
5044 status = MGMT_STATUS_FAILED;
5045 else
5046 status = MGMT_STATUS_SUCCESS;
5047
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005048 err = mgmt_cmd_complete(sk, hdev->id,
5049 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
5050 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08005051 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
5052 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005053 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08005054 u8 status;
5055
Johan Hedberg86df9202014-10-26 20:52:27 +01005056 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02005057 /* Enforce zero-valued 192-bit parameters as
5058 * long as legacy SMP OOB isn't implemented.
5059 */
5060 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
5061 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005062 err = mgmt_cmd_complete(sk, hdev->id,
5063 MGMT_OP_ADD_REMOTE_OOB_DATA,
5064 MGMT_STATUS_INVALID_PARAMS,
5065 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02005066 goto unlock;
5067 }
5068
Johan Hedberg86df9202014-10-26 20:52:27 +01005069 rand192 = NULL;
5070 hash192 = NULL;
5071 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005072 /* In case one of the P-192 values is set to zero,
5073 * then just disable OOB data for P-192.
5074 */
5075 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
5076 !memcmp(cp->hash192, ZERO_KEY, 16)) {
5077 rand192 = NULL;
5078 hash192 = NULL;
5079 } else {
5080 rand192 = cp->rand192;
5081 hash192 = cp->hash192;
5082 }
5083 }
5084
5085 /* In case one of the P-256 values is set to zero, then just
5086 * disable OOB data for P-256.
5087 */
5088 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
5089 !memcmp(cp->hash256, ZERO_KEY, 16)) {
5090 rand256 = NULL;
5091 hash256 = NULL;
5092 } else {
5093 rand256 = cp->rand256;
5094 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01005095 }
5096
Johan Hedberg81328d5c2014-10-26 20:33:47 +01005097 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01005098 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005099 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08005100 if (err < 0)
5101 status = MGMT_STATUS_FAILED;
5102 else
5103 status = MGMT_STATUS_SUCCESS;
5104
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005105 err = mgmt_cmd_complete(sk, hdev->id,
5106 MGMT_OP_ADD_REMOTE_OOB_DATA,
5107 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08005108 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005109 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
5110 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005111 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
5112 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08005113 }
Szymon Janc2763eda2011-03-22 13:12:22 +01005114
Johan Hedbergc19a4952014-11-17 20:52:19 +02005115unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005116 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005117 return err;
5118}
5119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005120static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005121 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01005122{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005123 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005124 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01005125 int err;
5126
Marcel Holtmann181d6952020-05-06 09:57:47 +02005127 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01005128
Johan Hedbergc19a4952014-11-17 20:52:19 +02005129 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005130 return mgmt_cmd_complete(sk, hdev->id,
5131 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5132 MGMT_STATUS_INVALID_PARAMS,
5133 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02005134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005135 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005136
Johan Hedbergeedbd582014-11-15 09:34:23 +02005137 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5138 hci_remote_oob_data_clear(hdev);
5139 status = MGMT_STATUS_SUCCESS;
5140 goto done;
5141 }
5142
Johan Hedberg6928a922014-10-26 20:46:09 +01005143 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01005144 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005145 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01005146 else
Szymon Janca6785be2012-12-13 15:11:21 +01005147 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005148
Johan Hedbergeedbd582014-11-15 09:34:23 +02005149done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005150 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5151 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01005152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005153 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005154 return err;
5155}
5156
Johan Hedberge68f0722015-11-11 08:30:30 +02005157void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03005158{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005159 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01005160
Kai Ye85d672842021-06-03 15:41:02 +08005161 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes7c307722013-04-30 15:29:28 -03005162
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005163 hci_dev_lock(hdev);
5164
Johan Hedberg333ae952015-03-17 13:48:47 +02005165 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005166 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02005167 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005168
Johan Hedberg78b781c2016-01-05 13:19:32 +02005169 if (!cmd)
5170 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
5171
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005172 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005173 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005174 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03005175 }
5176
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005177 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03005178}
5179
Johan Hedberg591752a2015-11-11 08:11:24 +02005180static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
5181 uint8_t *mgmt_status)
5182{
5183 switch (type) {
5184 case DISCOV_TYPE_LE:
5185 *mgmt_status = mgmt_le_support(hdev);
5186 if (*mgmt_status)
5187 return false;
5188 break;
5189 case DISCOV_TYPE_INTERLEAVED:
5190 *mgmt_status = mgmt_le_support(hdev);
5191 if (*mgmt_status)
5192 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05005193 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02005194 case DISCOV_TYPE_BREDR:
5195 *mgmt_status = mgmt_bredr_support(hdev);
5196 if (*mgmt_status)
5197 return false;
5198 break;
5199 default:
5200 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
5201 return false;
5202 }
5203
5204 return true;
5205}
5206
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005207static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
5208{
5209 struct mgmt_pending_cmd *cmd = data;
5210
5211 bt_dev_dbg(hdev, "err %d", err);
5212
5213 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5214 cmd->param, 1);
5215 mgmt_pending_free(cmd);
5216
Luiz Augusto von Dentz182ee452021-10-27 16:59:00 -07005217 hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005218 DISCOVERY_FINDING);
5219}
5220
5221static int start_discovery_sync(struct hci_dev *hdev, void *data)
5222{
5223 return hci_start_discovery_sync(hdev);
5224}
5225
Johan Hedberg78b781c2016-01-05 13:19:32 +02005226static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
5227 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005228{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005229 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005230 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01005231 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04005232 int err;
5233
Marcel Holtmann181d6952020-05-06 09:57:47 +02005234 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005235
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005236 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005237
Johan Hedberg4b34ee782012-02-21 14:13:02 +02005238 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005239 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005240 MGMT_STATUS_NOT_POWERED,
5241 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02005242 goto failed;
5243 }
5244
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005245 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005246 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005247 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5248 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03005249 goto failed;
5250 }
5251
Johan Hedberg591752a2015-11-11 08:11:24 +02005252 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005253 err = mgmt_cmd_complete(sk, hdev->id, op, status,
5254 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02005255 goto failed;
5256 }
5257
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005258 /* Can't start discovery when it is paused */
5259 if (hdev->discovery_paused) {
5260 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5261 &cp->type, sizeof(cp->type));
5262 goto failed;
5263 }
5264
Marcel Holtmann22078802014-12-05 11:45:22 +01005265 /* Clear the discovery filter first to free any previously
5266 * allocated memory for the UUID list.
5267 */
5268 hci_discovery_filter_clear(hdev);
5269
Andre Guedes4aab14e2012-02-17 20:39:36 -03005270 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01005271 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02005272 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
5273 hdev->discovery.limited = true;
5274 else
5275 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03005276
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005277 cmd = mgmt_pending_new(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02005278 if (!cmd) {
5279 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02005280 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03005281 }
Andre Guedes3fd24152012-02-03 17:48:01 -03005282
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005283 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5284 start_discovery_complete);
5285 if (err < 0) {
5286 mgmt_pending_free(cmd);
5287 goto failed;
5288 }
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005289
5290 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005291
5292failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005293 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005294 return err;
5295}
5296
Johan Hedberg78b781c2016-01-05 13:19:32 +02005297static int start_discovery(struct sock *sk, struct hci_dev *hdev,
5298 void *data, u16 len)
5299{
5300 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
5301 data, len);
5302}
5303
5304static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
5305 void *data, u16 len)
5306{
5307 return start_discovery_internal(sk, hdev,
5308 MGMT_OP_START_LIMITED_DISCOVERY,
5309 data, len);
5310}
5311
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005312static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
5313 void *data, u16 len)
5314{
5315 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005316 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005317 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
5318 u16 uuid_count, expected_len;
5319 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03005320 int err;
5321
Marcel Holtmann181d6952020-05-06 09:57:47 +02005322 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005323
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005324 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005325
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005326 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005327 err = mgmt_cmd_complete(sk, hdev->id,
5328 MGMT_OP_START_SERVICE_DISCOVERY,
5329 MGMT_STATUS_NOT_POWERED,
5330 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005331 goto failed;
5332 }
5333
5334 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005335 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005336 err = mgmt_cmd_complete(sk, hdev->id,
5337 MGMT_OP_START_SERVICE_DISCOVERY,
5338 MGMT_STATUS_BUSY, &cp->type,
5339 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005340 goto failed;
5341 }
5342
Abhishek Pandit-Subedi36211f72020-12-17 15:04:08 -08005343 if (hdev->discovery_paused) {
5344 err = mgmt_cmd_complete(sk, hdev->id,
5345 MGMT_OP_START_SERVICE_DISCOVERY,
5346 MGMT_STATUS_BUSY, &cp->type,
5347 sizeof(cp->type));
5348 goto failed;
5349 }
5350
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005351 uuid_count = __le16_to_cpu(cp->uuid_count);
5352 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005353 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
5354 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005355 err = mgmt_cmd_complete(sk, hdev->id,
5356 MGMT_OP_START_SERVICE_DISCOVERY,
5357 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5358 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005359 goto failed;
5360 }
5361
5362 expected_len = sizeof(*cp) + uuid_count * 16;
5363 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005364 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
5365 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005366 err = mgmt_cmd_complete(sk, hdev->id,
5367 MGMT_OP_START_SERVICE_DISCOVERY,
5368 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5369 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005370 goto failed;
5371 }
5372
Johan Hedberg591752a2015-11-11 08:11:24 +02005373 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
5374 err = mgmt_cmd_complete(sk, hdev->id,
5375 MGMT_OP_START_SERVICE_DISCOVERY,
5376 status, &cp->type, sizeof(cp->type));
5377 goto failed;
5378 }
5379
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005380 cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02005381 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005382 if (!cmd) {
5383 err = -ENOMEM;
5384 goto failed;
5385 }
5386
Marcel Holtmann22078802014-12-05 11:45:22 +01005387 /* Clear the discovery filter first to free any previously
5388 * allocated memory for the UUID list.
5389 */
5390 hci_discovery_filter_clear(hdev);
5391
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08005392 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005393 hdev->discovery.type = cp->type;
5394 hdev->discovery.rssi = cp->rssi;
5395 hdev->discovery.uuid_count = uuid_count;
5396
5397 if (uuid_count > 0) {
5398 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
5399 GFP_KERNEL);
5400 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005401 err = mgmt_cmd_complete(sk, hdev->id,
5402 MGMT_OP_START_SERVICE_DISCOVERY,
5403 MGMT_STATUS_FAILED,
5404 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005405 mgmt_pending_remove(cmd);
5406 goto failed;
5407 }
5408 }
5409
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005410 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5411 start_discovery_complete);
5412 if (err < 0) {
5413 mgmt_pending_free(cmd);
5414 goto failed;
5415 }
5416
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005417 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
5418
5419failed:
5420 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005421 return err;
5422}
5423
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005424void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03005425{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005426 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005427
Kai Ye85d672842021-06-03 15:41:02 +08005428 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005429
5430 hci_dev_lock(hdev);
5431
Johan Hedberg333ae952015-03-17 13:48:47 +02005432 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005433 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005434 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005435 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005436 }
5437
Andre Guedes0e05bba2013-04-30 15:29:33 -03005438 hci_dev_unlock(hdev);
5439}
5440
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005441static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
5442{
5443 struct mgmt_pending_cmd *cmd = data;
5444
5445 bt_dev_dbg(hdev, "err %d", err);
5446
5447 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5448 cmd->param, 1);
5449 mgmt_pending_free(cmd);
5450
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005451 if (!err)
5452 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
5453}
5454
5455static int stop_discovery_sync(struct hci_dev *hdev, void *data)
5456{
5457 return hci_stop_discovery_sync(hdev);
5458}
5459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005460static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005461 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005462{
Johan Hedbergd9306502012-02-20 23:25:18 +02005463 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005464 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04005465 int err;
5466
Marcel Holtmann181d6952020-05-06 09:57:47 +02005467 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005468
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005469 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005470
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005471 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005472 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5473 MGMT_STATUS_REJECTED, &mgmt_cp->type,
5474 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02005475 goto unlock;
5476 }
5477
5478 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005479 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5480 MGMT_STATUS_INVALID_PARAMS,
5481 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005482 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02005483 }
5484
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005485 cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04005486 if (!cmd) {
5487 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005488 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04005489 }
5490
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005491 err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd,
5492 stop_discovery_complete);
5493 if (err < 0) {
5494 mgmt_pending_free(cmd);
5495 goto unlock;
5496 }
Johan Hedberg2922a942014-12-05 13:36:06 +02005497
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005498 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005499
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005501 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005502 return err;
5503}
5504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005505static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005506 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02005507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005508 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005509 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005510 int err;
5511
Marcel Holtmann181d6952020-05-06 09:57:47 +02005512 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005513
Johan Hedberg561aafb2012-01-04 13:31:59 +02005514 hci_dev_lock(hdev);
5515
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005516 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005517 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5518 MGMT_STATUS_FAILED, &cp->addr,
5519 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005520 goto failed;
5521 }
5522
Johan Hedberga198e7b2012-02-17 14:27:06 +02005523 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005524 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005525 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5526 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
5527 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005528 goto failed;
5529 }
5530
5531 if (cp->name_known) {
5532 e->name_state = NAME_KNOWN;
5533 list_del(&e->list);
5534 } else {
5535 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02005536 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005537 }
5538
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005539 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
5540 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005541
5542failed:
5543 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005544 return err;
5545}
5546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005547static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005548 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005549{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005550 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005551 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005552 int err;
5553
Marcel Holtmann181d6952020-05-06 09:57:47 +02005554 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005555
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005556 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005557 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
5558 MGMT_STATUS_INVALID_PARAMS,
5559 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005561 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005562
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005563 err = hci_bdaddr_list_add(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005564 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005565 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005566 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005567 goto done;
5568 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005569
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005570 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5571 sk);
5572 status = MGMT_STATUS_SUCCESS;
5573
5574done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
5576 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005577
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005578 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005579
5580 return err;
5581}
5582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005583static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005584 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005585{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005586 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005587 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005588 int err;
5589
Marcel Holtmann181d6952020-05-06 09:57:47 +02005590 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005591
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005592 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005593 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5594 MGMT_STATUS_INVALID_PARAMS,
5595 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005597 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005598
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005599 err = hci_bdaddr_list_del(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005600 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005601 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005602 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005603 goto done;
5604 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005605
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005606 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5607 sk);
5608 status = MGMT_STATUS_SUCCESS;
5609
5610done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005611 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5612 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005613
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005614 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005615
5616 return err;
5617}
5618
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005619static int set_device_id_sync(struct hci_dev *hdev, void *data)
5620{
5621 return hci_update_eir_sync(hdev);
5622}
5623
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005624static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5625 u16 len)
5626{
5627 struct mgmt_cp_set_device_id *cp = data;
5628 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005629 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005630
Marcel Holtmann181d6952020-05-06 09:57:47 +02005631 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005632
Szymon Jancc72d4b82012-03-16 16:02:57 +01005633 source = __le16_to_cpu(cp->source);
5634
5635 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005636 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5637 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005638
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005639 hci_dev_lock(hdev);
5640
Szymon Jancc72d4b82012-03-16 16:02:57 +01005641 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005642 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5643 hdev->devid_product = __le16_to_cpu(cp->product);
5644 hdev->devid_version = __le16_to_cpu(cp->version);
5645
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005646 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5647 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005648
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005649 hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005650
5651 hci_dev_unlock(hdev);
5652
5653 return err;
5654}
5655
Brian Gix26ac4c52021-10-27 16:58:56 -07005656static void enable_advertising_instance(struct hci_dev *hdev, int err)
Arman Uguray24b4f382015-03-23 15:57:12 -07005657{
Brian Gix26ac4c52021-10-27 16:58:56 -07005658 if (err)
5659 bt_dev_err(hdev, "failed to re-configure advertising %d", err);
5660 else
5661 bt_dev_dbg(hdev, "status %d", err);
Arman Uguray24b4f382015-03-23 15:57:12 -07005662}
5663
Brian Gix26ac4c52021-10-27 16:58:56 -07005664static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg4375f102013-09-25 13:26:10 +03005665{
5666 struct cmd_lookup match = { NULL, hdev };
Florian Grandel7816b822015-06-18 03:16:45 +02005667 u8 instance;
5668 struct adv_info *adv_instance;
Brian Gix26ac4c52021-10-27 16:58:56 -07005669 u8 status = mgmt_status(err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305670
Johan Hedberg4375f102013-09-25 13:26:10 +03005671 if (status) {
Johan Hedberg4375f102013-09-25 13:26:10 +03005672 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
Brian Gix26ac4c52021-10-27 16:58:56 -07005673 cmd_status_rsp, &status);
5674 return;
Johan Hedberg4375f102013-09-25 13:26:10 +03005675 }
5676
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005677 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005678 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005679 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005680 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005681
Johan Hedberg4375f102013-09-25 13:26:10 +03005682 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5683 &match);
5684
5685 new_settings(hdev, match.sk);
5686
5687 if (match.sk)
5688 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305689
Arman Uguray24b4f382015-03-23 15:57:12 -07005690 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005691 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005692 */
5693 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005694 list_empty(&hdev->adv_instances))
Brian Gix26ac4c52021-10-27 16:58:56 -07005695 return;
Arman Uguray24b4f382015-03-23 15:57:12 -07005696
Florian Grandel7816b822015-06-18 03:16:45 +02005697 instance = hdev->cur_adv_instance;
5698 if (!instance) {
5699 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5700 struct adv_info, list);
5701 if (!adv_instance)
Brian Gix26ac4c52021-10-27 16:58:56 -07005702 return;
Florian Grandel7816b822015-06-18 03:16:45 +02005703
5704 instance = adv_instance->instance;
5705 }
5706
Brian Gix26ac4c52021-10-27 16:58:56 -07005707 err = hci_schedule_adv_instance_sync(hdev, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005708
Brian Gix26ac4c52021-10-27 16:58:56 -07005709 enable_advertising_instance(hdev, err);
5710}
Arman Uguray24b4f382015-03-23 15:57:12 -07005711
Brian Gix26ac4c52021-10-27 16:58:56 -07005712static int set_adv_sync(struct hci_dev *hdev, void *data)
5713{
5714 struct mgmt_pending_cmd *cmd = data;
5715 struct mgmt_mode *cp = cmd->param;
5716 u8 val = !!cp->val;
Florian Grandel7816b822015-06-18 03:16:45 +02005717
Brian Gix26ac4c52021-10-27 16:58:56 -07005718 if (cp->val == 0x02)
5719 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
5720 else
5721 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Arman Uguray24b4f382015-03-23 15:57:12 -07005722
Brian Gix26ac4c52021-10-27 16:58:56 -07005723 cancel_adv_timeout(hdev);
5724
5725 if (val) {
5726 /* Switch to instance "0" for the Set Advertising setting.
5727 * We cannot use update_[adv|scan_rsp]_data() here as the
5728 * HCI_ADVERTISING flag is not yet set.
5729 */
5730 hdev->cur_adv_instance = 0x00;
5731
5732 if (ext_adv_capable(hdev)) {
5733 hci_start_ext_adv_sync(hdev, 0x00);
5734 } else {
5735 hci_update_adv_data_sync(hdev, 0x00);
5736 hci_update_scan_rsp_data_sync(hdev, 0x00);
5737 hci_enable_advertising_sync(hdev);
5738 }
5739 } else {
5740 hci_disable_advertising_sync(hdev);
5741 }
5742
5743 return 0;
Johan Hedberg4375f102013-09-25 13:26:10 +03005744}
5745
Marcel Holtmann21b51872013-10-10 09:47:53 -07005746static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5747 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005748{
5749 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005750 struct mgmt_pending_cmd *cmd;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005751 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005752 int err;
5753
Marcel Holtmann181d6952020-05-06 09:57:47 +02005754 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005755
Johan Hedberge6fe7982013-10-02 15:45:22 +03005756 status = mgmt_le_support(hdev);
5757 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005758 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5759 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005760
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005761 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005762 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005764
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005765 if (hdev->advertising_paused)
5766 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5767 MGMT_STATUS_BUSY);
5768
Johan Hedberg4375f102013-09-25 13:26:10 +03005769 hci_dev_lock(hdev);
5770
5771 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005772
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005773 /* The following conditions are ones which mean that we should
5774 * not do any HCI communication but directly send a mgmt
5775 * response to user space (after toggling the flag if
5776 * necessary).
5777 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005778 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005779 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5780 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005781 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005782 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005783 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005784 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005785
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005786 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005787 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005788 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005789 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005790 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005791 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005792 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005793 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005794 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005795 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005796 }
5797
5798 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5799 if (err < 0)
5800 goto unlock;
5801
5802 if (changed)
5803 err = new_settings(hdev, sk);
5804
5805 goto unlock;
5806 }
5807
Johan Hedberg333ae952015-03-17 13:48:47 +02005808 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5809 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005810 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5811 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005812 goto unlock;
5813 }
5814
5815 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
Brian Gix26ac4c52021-10-27 16:58:56 -07005816 if (!cmd)
Johan Hedberg4375f102013-09-25 13:26:10 +03005817 err = -ENOMEM;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005818 else
Brian Gix26ac4c52021-10-27 16:58:56 -07005819 err = hci_cmd_sync_queue(hdev, set_adv_sync, cmd,
5820 set_advertising_complete);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005821
Brian Gix26ac4c52021-10-27 16:58:56 -07005822 if (err < 0 && cmd)
Johan Hedberg4375f102013-09-25 13:26:10 +03005823 mgmt_pending_remove(cmd);
5824
5825unlock:
5826 hci_dev_unlock(hdev);
5827 return err;
5828}
5829
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005830static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5831 void *data, u16 len)
5832{
5833 struct mgmt_cp_set_static_address *cp = data;
5834 int err;
5835
Marcel Holtmann181d6952020-05-06 09:57:47 +02005836 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005837
Marcel Holtmann62af4442013-10-02 22:10:32 -07005838 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005839 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5840 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005841
5842 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005843 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5844 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005845
5846 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5847 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005848 return mgmt_cmd_status(sk, hdev->id,
5849 MGMT_OP_SET_STATIC_ADDRESS,
5850 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005851
5852 /* Two most significant bits shall be set */
5853 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005854 return mgmt_cmd_status(sk, hdev->id,
5855 MGMT_OP_SET_STATIC_ADDRESS,
5856 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005857 }
5858
5859 hci_dev_lock(hdev);
5860
5861 bacpy(&hdev->static_addr, &cp->bdaddr);
5862
Marcel Holtmann93690c22015-03-06 10:11:21 -08005863 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5864 if (err < 0)
5865 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005866
Marcel Holtmann93690c22015-03-06 10:11:21 -08005867 err = new_settings(hdev, sk);
5868
5869unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005870 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005871 return err;
5872}
5873
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005874static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5875 void *data, u16 len)
5876{
5877 struct mgmt_cp_set_scan_params *cp = data;
5878 __u16 interval, window;
5879 int err;
5880
Marcel Holtmann181d6952020-05-06 09:57:47 +02005881 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005882
5883 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005884 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5885 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005886
5887 interval = __le16_to_cpu(cp->interval);
5888
5889 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005890 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5891 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005892
5893 window = __le16_to_cpu(cp->window);
5894
5895 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005896 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5897 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005898
Marcel Holtmann899e1072013-10-14 09:55:32 -07005899 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005900 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5901 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005902
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005903 hci_dev_lock(hdev);
5904
5905 hdev->le_scan_interval = interval;
5906 hdev->le_scan_window = window;
5907
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005908 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5909 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005910
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005911 /* If background scan is running, restart it so new parameters are
5912 * loaded.
5913 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005914 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005915 hdev->discovery.state == DISCOVERY_STOPPED)
5916 hci_update_passive_scan(hdev);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005917
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005918 hci_dev_unlock(hdev);
5919
5920 return err;
5921}
5922
Brian Gix353a0242021-10-27 16:58:46 -07005923static void fast_connectable_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005924{
Brian Gix353a0242021-10-27 16:58:46 -07005925 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005926
Brian Gix353a0242021-10-27 16:58:46 -07005927 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005928
Brian Gix353a0242021-10-27 16:58:46 -07005929 if (err) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005930 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Brian Gix353a0242021-10-27 16:58:46 -07005931 mgmt_status(err));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005932 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005933 struct mgmt_mode *cp = cmd->param;
5934
5935 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005936 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005937 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005938 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005939
Johan Hedberg33e38b32013-03-15 17:07:05 -05005940 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5941 new_settings(hdev, cmd->sk);
5942 }
5943
Brian Gix353a0242021-10-27 16:58:46 -07005944 mgmt_pending_free(cmd);
5945}
Johan Hedberg33e38b32013-03-15 17:07:05 -05005946
Brian Gix353a0242021-10-27 16:58:46 -07005947static int write_fast_connectable_sync(struct hci_dev *hdev, void *data)
5948{
5949 struct mgmt_pending_cmd *cmd = data;
5950 struct mgmt_mode *cp = cmd->param;
5951
5952 return hci_write_fast_connectable_sync(hdev, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005953}
5954
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005955static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005956 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005957{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005958 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005959 struct mgmt_pending_cmd *cmd;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005960 int err;
5961
Marcel Holtmann181d6952020-05-06 09:57:47 +02005962 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005963
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005964 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005965 hdev->hci_ver < BLUETOOTH_VER_1_2)
Brian Gix353a0242021-10-27 16:58:46 -07005966 return mgmt_cmd_status(sk, hdev->id,
5967 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberga69e8372015-03-06 21:08:53 +02005968 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005969
Johan Hedberga7e80f22013-01-09 16:05:19 +02005970 if (cp->val != 0x00 && cp->val != 0x01)
Brian Gix353a0242021-10-27 16:58:46 -07005971 return mgmt_cmd_status(sk, hdev->id,
5972 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberga69e8372015-03-06 21:08:53 +02005973 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005974
Antti Julkuf6422ec2011-06-22 13:11:56 +03005975 hci_dev_lock(hdev);
5976
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005977 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Brian Gix353a0242021-10-27 16:58:46 -07005978 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005979 goto unlock;
5980 }
5981
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005982 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005983 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Brian Gix353a0242021-10-27 16:58:46 -07005984 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005985 new_settings(hdev, sk);
5986 goto unlock;
5987 }
5988
Brian Gix353a0242021-10-27 16:58:46 -07005989 cmd = mgmt_pending_new(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev, data,
5990 len);
5991 if (!cmd)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005992 err = -ENOMEM;
Brian Gix353a0242021-10-27 16:58:46 -07005993 else
5994 err = hci_cmd_sync_queue(hdev, write_fast_connectable_sync, cmd,
5995 fast_connectable_complete);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005996
Antti Julkuf6422ec2011-06-22 13:11:56 +03005997 if (err < 0) {
Brian Gix353a0242021-10-27 16:58:46 -07005998 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5999 MGMT_STATUS_FAILED);
6000
Brian Gix353a0242021-10-27 16:58:46 -07006001 if (cmd)
6002 mgmt_pending_free(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03006003 }
6004
Johan Hedberg33e38b32013-03-15 17:07:05 -05006005unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03006006 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05006007
Antti Julkuf6422ec2011-06-22 13:11:56 +03006008 return err;
6009}
6010
Brian Gix451d95a2021-10-27 16:58:47 -07006011static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg0663ca22013-10-02 13:43:14 +03006012{
Brian Gix451d95a2021-10-27 16:58:47 -07006013 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006014
Brian Gix451d95a2021-10-27 16:58:47 -07006015 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006016
Brian Gix451d95a2021-10-27 16:58:47 -07006017 if (err) {
6018 u8 mgmt_err = mgmt_status(err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006019
6020 /* We need to restore the flag if related HCI commands
6021 * failed.
6022 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006023 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006024
Johan Hedberga69e8372015-03-06 21:08:53 +02006025 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006026 } else {
6027 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
6028 new_settings(hdev, cmd->sk);
6029 }
6030
Brian Gix451d95a2021-10-27 16:58:47 -07006031 mgmt_pending_free(cmd);
6032}
Johan Hedberg0663ca22013-10-02 13:43:14 +03006033
Brian Gix451d95a2021-10-27 16:58:47 -07006034static int set_bredr_sync(struct hci_dev *hdev, void *data)
6035{
6036 int status;
6037
6038 status = hci_write_fast_connectable_sync(hdev, false);
6039
6040 if (!status)
6041 status = hci_update_scan_sync(hdev);
6042
6043 /* Since only the advertising data flags will change, there
6044 * is no need to update the scan response data.
6045 */
6046 if (!status)
6047 status = hci_update_adv_data_sync(hdev, hdev->cur_adv_instance);
6048
6049 return status;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006050}
6051
6052static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
6053{
6054 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006055 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006056 int err;
6057
Marcel Holtmann181d6952020-05-06 09:57:47 +02006058 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006059
6060 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006061 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6062 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006063
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006064 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006065 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6066 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006067
6068 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006069 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6070 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006071
6072 hci_dev_lock(hdev);
6073
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006074 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03006075 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6076 goto unlock;
6077 }
6078
6079 if (!hdev_is_powered(hdev)) {
6080 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006081 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
6082 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
6083 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
6084 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
6085 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006086 }
6087
Marcel Holtmannce05d602015-03-13 02:11:03 -07006088 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006089
6090 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6091 if (err < 0)
6092 goto unlock;
6093
6094 err = new_settings(hdev, sk);
6095 goto unlock;
6096 }
6097
6098 /* Reject disabling when powered on */
6099 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006100 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6101 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006102 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006103 } else {
6104 /* When configuring a dual-mode controller to operate
6105 * with LE only and using a static address, then switching
6106 * BR/EDR back on is not allowed.
6107 *
6108 * Dual-mode controllers shall operate with the public
6109 * address as its identity address for BR/EDR and LE. So
6110 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006111 *
6112 * The same restrictions applies when secure connections
6113 * has been enabled. For BR/EDR this is a controller feature
6114 * while for LE it is a host stack feature. This means that
6115 * switching BR/EDR back on when secure connections has been
6116 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006117 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006118 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006119 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006120 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006121 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6122 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006123 goto unlock;
6124 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03006125 }
6126
Brian Gix451d95a2021-10-27 16:58:47 -07006127 cmd = mgmt_pending_new(sk, MGMT_OP_SET_BREDR, hdev, data, len);
6128 if (!cmd)
Johan Hedberg0663ca22013-10-02 13:43:14 +03006129 err = -ENOMEM;
Brian Gix451d95a2021-10-27 16:58:47 -07006130 else
6131 err = hci_cmd_sync_queue(hdev, set_bredr_sync, cmd,
6132 set_bredr_complete);
6133
6134 if (err < 0) {
6135 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6136 MGMT_STATUS_FAILED);
6137 if (cmd)
6138 mgmt_pending_free(cmd);
6139
Johan Hedberg0663ca22013-10-02 13:43:14 +03006140 goto unlock;
6141 }
6142
Johan Hedbergf2252572015-11-18 12:49:20 +02006143 /* We need to flip the bit already here so that
6144 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03006145 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006146 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006147
Johan Hedberg0663ca22013-10-02 13:43:14 +03006148unlock:
6149 hci_dev_unlock(hdev);
6150 return err;
6151}
6152
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006153static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberga1443f52015-01-23 15:42:46 +02006154{
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006155 struct mgmt_pending_cmd *cmd = data;
Johan Hedberga1443f52015-01-23 15:42:46 +02006156 struct mgmt_mode *cp;
6157
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006158 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberga1443f52015-01-23 15:42:46 +02006159
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006160 if (err) {
6161 u8 mgmt_err = mgmt_status(err);
Johan Hedberga1443f52015-01-23 15:42:46 +02006162
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006163 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
6164 goto done;
Johan Hedberga1443f52015-01-23 15:42:46 +02006165 }
6166
6167 cp = cmd->param;
6168
6169 switch (cp->val) {
6170 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006171 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
6172 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006173 break;
6174 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006175 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006176 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006177 break;
6178 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006179 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
6180 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006181 break;
6182 }
6183
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006184 send_settings_rsp(cmd->sk, cmd->opcode, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02006185 new_settings(hdev, cmd->sk);
6186
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006187done:
6188 mgmt_pending_free(cmd);
6189}
6190
6191static int set_secure_conn_sync(struct hci_dev *hdev, void *data)
6192{
6193 struct mgmt_pending_cmd *cmd = data;
6194 struct mgmt_mode *cp = cmd->param;
6195 u8 val = !!cp->val;
6196
6197 /* Force write of val */
6198 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
6199
6200 return hci_write_sc_support_sync(hdev, val);
Johan Hedberga1443f52015-01-23 15:42:46 +02006201}
6202
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006203static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
6204 void *data, u16 len)
6205{
6206 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006207 struct mgmt_pending_cmd *cmd;
Johan Hedberga3209692014-05-26 11:23:35 +03006208 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006209 int err;
6210
Marcel Holtmann181d6952020-05-06 09:57:47 +02006211 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006212
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006213 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006214 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006215 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6216 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006217
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006218 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02006219 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006220 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006221 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6222 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08006223
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006224 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006225 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006226 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006227
6228 hci_dev_lock(hdev);
6229
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006230 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006231 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006232 bool changed;
6233
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006234 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006235 changed = !hci_dev_test_and_set_flag(hdev,
6236 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006237 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006238 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006239 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006240 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006241 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006242 changed = hci_dev_test_and_clear_flag(hdev,
6243 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006244 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006245 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006246
6247 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6248 if (err < 0)
6249 goto failed;
6250
6251 if (changed)
6252 err = new_settings(hdev, sk);
6253
6254 goto failed;
6255 }
6256
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006257 val = !!cp->val;
6258
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006259 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6260 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006261 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6262 goto failed;
6263 }
6264
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006265 cmd = mgmt_pending_new(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
6266 if (!cmd)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006267 err = -ENOMEM;
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006268 else
6269 err = hci_cmd_sync_queue(hdev, set_secure_conn_sync, cmd,
6270 set_secure_conn_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006271
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006272 if (err < 0) {
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006273 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6274 MGMT_STATUS_FAILED);
6275 if (cmd)
6276 mgmt_pending_free(cmd);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006277 }
6278
6279failed:
6280 hci_dev_unlock(hdev);
6281 return err;
6282}
6283
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006284static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
6285 void *data, u16 len)
6286{
6287 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03006288 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006289 int err;
6290
Marcel Holtmann181d6952020-05-06 09:57:47 +02006291 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006292
Johan Hedbergb97109792014-06-24 14:00:28 +03006293 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006294 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
6295 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006296
6297 hci_dev_lock(hdev);
6298
6299 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07006300 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006301 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006302 changed = hci_dev_test_and_clear_flag(hdev,
6303 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006304
Johan Hedbergb97109792014-06-24 14:00:28 +03006305 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07006306 use_changed = !hci_dev_test_and_set_flag(hdev,
6307 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006308 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006309 use_changed = hci_dev_test_and_clear_flag(hdev,
6310 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006311
6312 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006313 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03006314 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
6315 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
6316 sizeof(mode), &mode);
6317 }
6318
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006319 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
6320 if (err < 0)
6321 goto unlock;
6322
6323 if (changed)
6324 err = new_settings(hdev, sk);
6325
6326unlock:
6327 hci_dev_unlock(hdev);
6328 return err;
6329}
6330
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006331static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6332 u16 len)
6333{
6334 struct mgmt_cp_set_privacy *cp = cp_data;
6335 bool changed;
6336 int err;
6337
Marcel Holtmann181d6952020-05-06 09:57:47 +02006338 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006339
6340 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006341 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6342 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006343
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006344 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006345 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6346 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006347
6348 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006349 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6350 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006351
6352 hci_dev_lock(hdev);
6353
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006354 /* If user space supports this command it is also expected to
6355 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
6356 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006357 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006358
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006359 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006360 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006361 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006362 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306363 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006364 if (cp->privacy == 0x02)
6365 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
6366 else
6367 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006368 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006369 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006370 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006371 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306372 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006373 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006374 }
6375
6376 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
6377 if (err < 0)
6378 goto unlock;
6379
6380 if (changed)
6381 err = new_settings(hdev, sk);
6382
6383unlock:
6384 hci_dev_unlock(hdev);
6385 return err;
6386}
6387
Johan Hedberg41edf162014-02-18 10:19:35 +02006388static bool irk_is_valid(struct mgmt_irk_info *irk)
6389{
6390 switch (irk->addr.type) {
6391 case BDADDR_LE_PUBLIC:
6392 return true;
6393
6394 case BDADDR_LE_RANDOM:
6395 /* Two most significant bits shall be set */
6396 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6397 return false;
6398 return true;
6399 }
6400
6401 return false;
6402}
6403
6404static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6405 u16 len)
6406{
6407 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006408 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
6409 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02006410 u16 irk_count, expected_len;
6411 int i, err;
6412
Marcel Holtmann181d6952020-05-06 09:57:47 +02006413 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02006414
6415 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006416 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6417 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02006418
6419 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006420 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006421 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
6422 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006425 }
Johan Hedberg41edf162014-02-18 10:19:35 +02006426
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006427 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006428 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006429 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
6430 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006431 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6432 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006433 }
6434
Marcel Holtmann181d6952020-05-06 09:57:47 +02006435 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006436
6437 for (i = 0; i < irk_count; i++) {
6438 struct mgmt_irk_info *key = &cp->irks[i];
6439
6440 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006441 return mgmt_cmd_status(sk, hdev->id,
6442 MGMT_OP_LOAD_IRKS,
6443 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006444 }
6445
6446 hci_dev_lock(hdev);
6447
6448 hci_smp_irks_clear(hdev);
6449
6450 for (i = 0; i < irk_count; i++) {
6451 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02006452
Alain Michaud600a8742020-01-07 00:43:17 +00006453 if (hci_is_blocked_key(hdev,
6454 HCI_BLOCKED_KEY_TYPE_IRK,
6455 irk->val)) {
6456 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
6457 &irk->addr.bdaddr);
6458 continue;
6459 }
6460
Johan Hedberg85813a72015-10-21 18:02:59 +03006461 hci_add_irk(hdev, &irk->addr.bdaddr,
6462 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02006463 BDADDR_ANY);
6464 }
6465
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006466 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02006467
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02006469
6470 hci_dev_unlock(hdev);
6471
6472 return err;
6473}
6474
Johan Hedberg3f706b72013-01-20 14:27:16 +02006475static bool ltk_is_valid(struct mgmt_ltk_info *key)
6476{
Archie Pusakafad646e2021-05-31 16:37:25 +08006477 if (key->initiator != 0x00 && key->initiator != 0x01)
Johan Hedberg3f706b72013-01-20 14:27:16 +02006478 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08006479
6480 switch (key->addr.type) {
6481 case BDADDR_LE_PUBLIC:
6482 return true;
6483
6484 case BDADDR_LE_RANDOM:
6485 /* Two most significant bits shall be set */
6486 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6487 return false;
6488 return true;
6489 }
6490
6491 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02006492}
6493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006494static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006495 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006496{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006497 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006498 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
6499 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006500 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006501 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006502
Marcel Holtmann181d6952020-05-06 09:57:47 +02006503 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006504
6505 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006506 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6507 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006508
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006509 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006510 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006511 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
6512 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006513 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6514 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006515 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006516
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006517 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006518 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006519 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
6520 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6522 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006523 }
6524
Marcel Holtmann181d6952020-05-06 09:57:47 +02006525 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006526
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006527 for (i = 0; i < key_count; i++) {
6528 struct mgmt_ltk_info *key = &cp->keys[i];
6529
Johan Hedberg3f706b72013-01-20 14:27:16 +02006530 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006531 return mgmt_cmd_status(sk, hdev->id,
6532 MGMT_OP_LOAD_LONG_TERM_KEYS,
6533 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006534 }
6535
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006536 hci_dev_lock(hdev);
6537
6538 hci_smp_ltks_clear(hdev);
6539
6540 for (i = 0; i < key_count; i++) {
6541 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006542 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006543
Alain Michaud600a8742020-01-07 00:43:17 +00006544 if (hci_is_blocked_key(hdev,
6545 HCI_BLOCKED_KEY_TYPE_LTK,
6546 key->val)) {
6547 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6548 &key->addr.bdaddr);
6549 continue;
6550 }
6551
Johan Hedberg61b43352014-05-29 19:36:53 +03006552 switch (key->type) {
6553 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006554 authenticated = 0x00;
Archie Pusakafad646e2021-05-31 16:37:25 +08006555 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006556 break;
6557 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006558 authenticated = 0x01;
Archie Pusakafad646e2021-05-31 16:37:25 +08006559 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006560 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006561 case MGMT_LTK_P256_UNAUTH:
6562 authenticated = 0x00;
6563 type = SMP_LTK_P256;
6564 break;
6565 case MGMT_LTK_P256_AUTH:
6566 authenticated = 0x01;
6567 type = SMP_LTK_P256;
6568 break;
6569 case MGMT_LTK_P256_DEBUG:
6570 authenticated = 0x00;
6571 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006572 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006573 default:
6574 continue;
6575 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006576
Johan Hedberg85813a72015-10-21 18:02:59 +03006577 hci_add_ltk(hdev, &key->addr.bdaddr,
6578 le_addr_type(key->addr.type), type, authenticated,
6579 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006580 }
6581
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006582 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006583 NULL, 0);
6584
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006585 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006586
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006587 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006588}
6589
Brian Gix47db6b42021-10-27 16:58:48 -07006590static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006591{
Brian Gix47db6b42021-10-27 16:58:48 -07006592 struct mgmt_pending_cmd *cmd = data;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006593 struct hci_conn *conn = cmd->user_data;
Brian Gix47db6b42021-10-27 16:58:48 -07006594 struct mgmt_cp_get_conn_info *cp = cmd->param;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006595 struct mgmt_rp_get_conn_info rp;
Brian Gix47db6b42021-10-27 16:58:48 -07006596 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006597
Brian Gix47db6b42021-10-27 16:58:48 -07006598 bt_dev_dbg(hdev, "err %d", err);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006599
Brian Gix47db6b42021-10-27 16:58:48 -07006600 memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr));
6601
6602 status = mgmt_status(err);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006603 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006604 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006605 rp.tx_power = conn->tx_power;
6606 rp.max_tx_power = conn->max_tx_power;
6607 } else {
6608 rp.rssi = HCI_RSSI_INVALID;
6609 rp.tx_power = HCI_TX_POWER_INVALID;
6610 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006611 }
6612
Brian Gix47db6b42021-10-27 16:58:48 -07006613 mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
6614 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006615
Brian Gix47db6b42021-10-27 16:58:48 -07006616 if (conn) {
6617 hci_conn_drop(conn);
6618 hci_conn_put(conn);
6619 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006620
Brian Gix47db6b42021-10-27 16:58:48 -07006621 mgmt_pending_free(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006622}
6623
Brian Gix47db6b42021-10-27 16:58:48 -07006624static int get_conn_info_sync(struct hci_dev *hdev, void *data)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006625{
Brian Gix47db6b42021-10-27 16:58:48 -07006626 struct mgmt_pending_cmd *cmd = data;
6627 struct mgmt_cp_get_conn_info *cp = cmd->param;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006628 struct hci_conn *conn;
Brian Gix47db6b42021-10-27 16:58:48 -07006629 int err;
6630 __le16 handle;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006631
Brian Gix47db6b42021-10-27 16:58:48 -07006632 /* Make sure we are still connected */
6633 if (cp->addr.type == BDADDR_BREDR)
6634 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6635 &cp->addr.bdaddr);
6636 else
6637 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006638
Brian Gix47db6b42021-10-27 16:58:48 -07006639 if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) {
6640 if (cmd->user_data) {
6641 hci_conn_drop(cmd->user_data);
6642 hci_conn_put(cmd->user_data);
6643 cmd->user_data = NULL;
6644 }
6645 return MGMT_STATUS_NOT_CONNECTED;
6646 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006647
Brian Gix47db6b42021-10-27 16:58:48 -07006648 handle = cpu_to_le16(conn->handle);
6649
6650 /* Refresh RSSI each time */
6651 err = hci_read_rssi_sync(hdev, handle);
6652
6653 /* For LE links TX power does not change thus we don't need to
6654 * query for it once value is known.
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006655 */
Brian Gix47db6b42021-10-27 16:58:48 -07006656 if (!err && (!bdaddr_type_is_le(cp->addr.type) ||
6657 conn->tx_power == HCI_TX_POWER_INVALID))
6658 err = hci_read_tx_power_sync(hdev, handle, 0x00);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006659
Brian Gix47db6b42021-10-27 16:58:48 -07006660 /* Max TX power needs to be read only once per connection */
6661 if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID)
6662 err = hci_read_tx_power_sync(hdev, handle, 0x01);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006663
Brian Gix47db6b42021-10-27 16:58:48 -07006664 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006665}
6666
6667static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6668 u16 len)
6669{
6670 struct mgmt_cp_get_conn_info *cp = data;
6671 struct mgmt_rp_get_conn_info rp;
6672 struct hci_conn *conn;
6673 unsigned long conn_info_age;
6674 int err = 0;
6675
Marcel Holtmann181d6952020-05-06 09:57:47 +02006676 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006677
6678 memset(&rp, 0, sizeof(rp));
6679 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6680 rp.addr.type = cp->addr.type;
6681
6682 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006683 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6684 MGMT_STATUS_INVALID_PARAMS,
6685 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006686
6687 hci_dev_lock(hdev);
6688
6689 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006690 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6691 MGMT_STATUS_NOT_POWERED, &rp,
6692 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006693 goto unlock;
6694 }
6695
6696 if (cp->addr.type == BDADDR_BREDR)
6697 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6698 &cp->addr.bdaddr);
6699 else
6700 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6701
6702 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006703 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6704 MGMT_STATUS_NOT_CONNECTED, &rp,
6705 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006706 goto unlock;
6707 }
6708
6709 /* To avoid client trying to guess when to poll again for information we
6710 * calculate conn info age as random value between min/max set in hdev.
6711 */
6712 conn_info_age = hdev->conn_info_min_age +
6713 prandom_u32_max(hdev->conn_info_max_age -
6714 hdev->conn_info_min_age);
6715
6716 /* Query controller to refresh cached values if they are too old or were
6717 * never read.
6718 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006719 if (time_after(jiffies, conn->conn_info_timestamp +
6720 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006721 !conn->conn_info_timestamp) {
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006722 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006723
Brian Gix47db6b42021-10-27 16:58:48 -07006724 cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data,
6725 len);
6726 if (!cmd)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006727 err = -ENOMEM;
Brian Gix47db6b42021-10-27 16:58:48 -07006728 else
6729 err = hci_cmd_sync_queue(hdev, get_conn_info_sync,
6730 cmd, get_conn_info_complete);
6731
6732 if (err < 0) {
6733 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6734 MGMT_STATUS_FAILED, &rp, sizeof(rp));
6735
6736 if (cmd)
6737 mgmt_pending_free(cmd);
6738
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006739 goto unlock;
6740 }
6741
6742 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006743 cmd->user_data = hci_conn_get(conn);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006744
6745 conn->conn_info_timestamp = jiffies;
6746 } else {
6747 /* Cache is valid, just reply with values cached in hci_conn */
6748 rp.rssi = conn->rssi;
6749 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006750 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006751
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006752 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6753 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006754 }
6755
6756unlock:
6757 hci_dev_unlock(hdev);
6758 return err;
6759}
6760
Brian Gix5a750132021-10-27 16:58:50 -07006761static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg69487372014-12-05 13:36:07 +02006762{
Brian Gix5a750132021-10-27 16:58:50 -07006763 struct mgmt_pending_cmd *cmd = data;
6764 struct mgmt_cp_get_clock_info *cp = cmd->param;
Johan Hedberg69487372014-12-05 13:36:07 +02006765 struct mgmt_rp_get_clock_info rp;
Brian Gix5a750132021-10-27 16:58:50 -07006766 struct hci_conn *conn = cmd->user_data;
6767 u8 status = mgmt_status(err);
6768
6769 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg69487372014-12-05 13:36:07 +02006770
6771 memset(&rp, 0, sizeof(rp));
Brian Gix5a750132021-10-27 16:58:50 -07006772 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6773 rp.addr.type = cp->addr.type;
Johan Hedberg69487372014-12-05 13:36:07 +02006774
Brian Gix5a750132021-10-27 16:58:50 -07006775 if (err)
Johan Hedberg69487372014-12-05 13:36:07 +02006776 goto complete;
6777
Brian Gix5a750132021-10-27 16:58:50 -07006778 rp.local_clock = cpu_to_le32(hdev->clock);
Johan Hedberg69487372014-12-05 13:36:07 +02006779
6780 if (conn) {
6781 rp.piconet_clock = cpu_to_le32(conn->clock);
6782 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
Brian Gix5a750132021-10-27 16:58:50 -07006783 hci_conn_drop(conn);
6784 hci_conn_put(conn);
Johan Hedberg69487372014-12-05 13:36:07 +02006785 }
6786
6787complete:
Brian Gix5a750132021-10-27 16:58:50 -07006788 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6789 sizeof(rp));
6790
6791 mgmt_pending_free(cmd);
6792}
6793
6794static int get_clock_info_sync(struct hci_dev *hdev, void *data)
6795{
6796 struct mgmt_pending_cmd *cmd = data;
6797 struct mgmt_cp_get_clock_info *cp = cmd->param;
6798 struct hci_cp_read_clock hci_cp;
6799 struct hci_conn *conn = cmd->user_data;
6800 int err;
6801
6802 memset(&hci_cp, 0, sizeof(hci_cp));
6803 err = hci_read_clock_sync(hdev, &hci_cp);
Johan Hedberg69487372014-12-05 13:36:07 +02006804
6805 if (conn) {
Brian Gix5a750132021-10-27 16:58:50 -07006806 /* Make sure connection still exists */
6807 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6808 &cp->addr.bdaddr);
6809
6810 if (conn && conn == cmd->user_data &&
6811 conn->state == BT_CONNECTED) {
6812 hci_cp.handle = cpu_to_le16(conn->handle);
6813 hci_cp.which = 0x01; /* Piconet clock */
6814 err = hci_read_clock_sync(hdev, &hci_cp);
6815 } else if (cmd->user_data) {
6816 hci_conn_drop(cmd->user_data);
6817 hci_conn_put(cmd->user_data);
6818 cmd->user_data = NULL;
6819 }
Johan Hedberg69487372014-12-05 13:36:07 +02006820 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006821
6822 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006823}
6824
Johan Hedberg95868422014-06-28 17:54:07 +03006825static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
Brian Gix5a750132021-10-27 16:58:50 -07006826 u16 len)
Johan Hedberg95868422014-06-28 17:54:07 +03006827{
6828 struct mgmt_cp_get_clock_info *cp = data;
6829 struct mgmt_rp_get_clock_info rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006830 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006831 struct hci_conn *conn;
6832 int err;
6833
Marcel Holtmann181d6952020-05-06 09:57:47 +02006834 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006835
6836 memset(&rp, 0, sizeof(rp));
6837 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6838 rp.addr.type = cp->addr.type;
6839
6840 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006841 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6842 MGMT_STATUS_INVALID_PARAMS,
6843 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006844
6845 hci_dev_lock(hdev);
6846
6847 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006848 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6849 MGMT_STATUS_NOT_POWERED, &rp,
6850 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006851 goto unlock;
6852 }
6853
6854 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6855 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6856 &cp->addr.bdaddr);
6857 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006858 err = mgmt_cmd_complete(sk, hdev->id,
6859 MGMT_OP_GET_CLOCK_INFO,
6860 MGMT_STATUS_NOT_CONNECTED,
6861 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006862 goto unlock;
6863 }
6864 } else {
6865 conn = NULL;
6866 }
6867
Brian Gix5a750132021-10-27 16:58:50 -07006868 cmd = mgmt_pending_new(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6869 if (!cmd)
Johan Hedberg95868422014-06-28 17:54:07 +03006870 err = -ENOMEM;
Brian Gix5a750132021-10-27 16:58:50 -07006871 else
6872 err = hci_cmd_sync_queue(hdev, get_clock_info_sync, cmd,
6873 get_clock_info_complete);
Johan Hedberg95868422014-06-28 17:54:07 +03006874
Brian Gix5a750132021-10-27 16:58:50 -07006875 if (err < 0) {
6876 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6877 MGMT_STATUS_FAILED, &rp, sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006878
Brian Gix5a750132021-10-27 16:58:50 -07006879 if (cmd)
6880 mgmt_pending_free(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006881
Brian Gix5a750132021-10-27 16:58:50 -07006882 } else if (conn) {
Johan Hedberg95868422014-06-28 17:54:07 +03006883 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006884 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006885 }
6886
Johan Hedberg95868422014-06-28 17:54:07 +03006887
6888unlock:
6889 hci_dev_unlock(hdev);
6890 return err;
6891}
6892
Johan Hedberg5a154e62014-12-19 22:26:02 +02006893static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6894{
6895 struct hci_conn *conn;
6896
6897 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6898 if (!conn)
6899 return false;
6900
6901 if (conn->dst_type != type)
6902 return false;
6903
6904 if (conn->state != BT_CONNECTED)
6905 return false;
6906
6907 return true;
6908}
6909
6910/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006911static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006912 u8 addr_type, u8 auto_connect)
6913{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006914 struct hci_conn_params *params;
6915
6916 params = hci_conn_params_add(hdev, addr, addr_type);
6917 if (!params)
6918 return -EIO;
6919
6920 if (params->auto_connect == auto_connect)
6921 return 0;
6922
6923 list_del_init(&params->action);
6924
6925 switch (auto_connect) {
6926 case HCI_AUTO_CONN_DISABLED:
6927 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006928 /* If auto connect is being disabled when we're trying to
6929 * connect to device, keep connecting.
6930 */
6931 if (params->explicit_connect)
6932 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006933 break;
6934 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006935 if (params->explicit_connect)
6936 list_add(&params->action, &hdev->pend_le_conns);
6937 else
6938 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006939 break;
6940 case HCI_AUTO_CONN_DIRECT:
6941 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006942 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006943 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006944 break;
6945 }
6946
6947 params->auto_connect = auto_connect;
6948
Marcel Holtmann181d6952020-05-06 09:57:47 +02006949 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6950 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006951
6952 return 0;
6953}
6954
Marcel Holtmann8afef092014-06-29 22:28:34 +02006955static void device_added(struct sock *sk, struct hci_dev *hdev,
6956 bdaddr_t *bdaddr, u8 type, u8 action)
6957{
6958 struct mgmt_ev_device_added ev;
6959
6960 bacpy(&ev.addr.bdaddr, bdaddr);
6961 ev.addr.type = type;
6962 ev.action = action;
6963
6964 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6965}
6966
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07006967static int add_device_sync(struct hci_dev *hdev, void *data)
6968{
6969 return hci_update_passive_scan_sync(hdev);
6970}
6971
Marcel Holtmann2faade52014-06-29 19:44:03 +02006972static int add_device(struct sock *sk, struct hci_dev *hdev,
6973 void *data, u16 len)
6974{
6975 struct mgmt_cp_add_device *cp = data;
6976 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006977 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006978 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006979 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006980
Marcel Holtmann181d6952020-05-06 09:57:47 +02006981 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006982
Johan Hedberg66593582014-07-09 12:59:14 +03006983 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006984 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006985 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6986 MGMT_STATUS_INVALID_PARAMS,
6987 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006988
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006989 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006990 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6991 MGMT_STATUS_INVALID_PARAMS,
6992 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006993
6994 hci_dev_lock(hdev);
6995
Johan Hedberg66593582014-07-09 12:59:14 +03006996 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006997 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006998 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006999 err = mgmt_cmd_complete(sk, hdev->id,
7000 MGMT_OP_ADD_DEVICE,
7001 MGMT_STATUS_INVALID_PARAMS,
7002 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007003 goto unlock;
7004 }
7005
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007006 err = hci_bdaddr_list_add_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02007007 &cp->addr.bdaddr,
7008 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03007009 if (err)
7010 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03007011
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007012 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007013
Johan Hedberg66593582014-07-09 12:59:14 +03007014 goto added;
7015 }
7016
Johan Hedberg85813a72015-10-21 18:02:59 +03007017 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007018
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007019 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02007020 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007021 else if (cp->action == 0x01)
7022 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007023 else
Johan Hedberga3451d22014-07-02 17:37:27 +03007024 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007025
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007026 /* Kernel internally uses conn_params with resolvable private
7027 * address, but Add Device allows only identity addresses.
7028 * Make sure it is enforced before calling
7029 * hci_conn_params_lookup.
7030 */
7031 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007032 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7033 MGMT_STATUS_INVALID_PARAMS,
7034 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007035 goto unlock;
7036 }
7037
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02007038 /* If the connection parameters don't exist for this device,
7039 * they will be created and configured with defaults.
7040 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02007041 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02007042 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007043 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7044 MGMT_STATUS_FAILED, &cp->addr,
7045 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007046 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007047 } else {
7048 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7049 addr_type);
7050 if (params)
7051 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007052 }
7053
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007054 err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
7055 if (err < 0)
7056 goto unlock;
Johan Hedberg51d7a942015-11-11 08:11:18 +02007057
Johan Hedberg66593582014-07-09 12:59:14 +03007058added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02007059 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007060 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
7061 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007062
Johan Hedberg51d7a942015-11-11 08:11:18 +02007063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7064 MGMT_STATUS_SUCCESS, &cp->addr,
7065 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007066
7067unlock:
7068 hci_dev_unlock(hdev);
7069 return err;
7070}
7071
Marcel Holtmann8afef092014-06-29 22:28:34 +02007072static void device_removed(struct sock *sk, struct hci_dev *hdev,
7073 bdaddr_t *bdaddr, u8 type)
7074{
7075 struct mgmt_ev_device_removed ev;
7076
7077 bacpy(&ev.addr.bdaddr, bdaddr);
7078 ev.addr.type = type;
7079
7080 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
7081}
7082
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007083static int remove_device_sync(struct hci_dev *hdev, void *data)
7084{
7085 return hci_update_passive_scan_sync(hdev);
7086}
7087
Marcel Holtmann2faade52014-06-29 19:44:03 +02007088static int remove_device(struct sock *sk, struct hci_dev *hdev,
7089 void *data, u16 len)
7090{
7091 struct mgmt_cp_remove_device *cp = data;
7092 int err;
7093
Marcel Holtmann181d6952020-05-06 09:57:47 +02007094 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007095
7096 hci_dev_lock(hdev);
7097
7098 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03007099 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007100 u8 addr_type;
7101
Johan Hedberg66593582014-07-09 12:59:14 +03007102 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007103 err = mgmt_cmd_complete(sk, hdev->id,
7104 MGMT_OP_REMOVE_DEVICE,
7105 MGMT_STATUS_INVALID_PARAMS,
7106 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007107 goto unlock;
7108 }
7109
Johan Hedberg66593582014-07-09 12:59:14 +03007110 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007111 err = hci_bdaddr_list_del(&hdev->accept_list,
Johan Hedberg66593582014-07-09 12:59:14 +03007112 &cp->addr.bdaddr,
7113 cp->addr.type);
7114 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007115 err = mgmt_cmd_complete(sk, hdev->id,
7116 MGMT_OP_REMOVE_DEVICE,
7117 MGMT_STATUS_INVALID_PARAMS,
7118 &cp->addr,
7119 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007120 goto unlock;
7121 }
7122
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007123 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007124
Johan Hedberg66593582014-07-09 12:59:14 +03007125 device_removed(sk, hdev, &cp->addr.bdaddr,
7126 cp->addr.type);
7127 goto complete;
7128 }
7129
Johan Hedberg85813a72015-10-21 18:02:59 +03007130 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007131
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007132 /* Kernel internally uses conn_params with resolvable private
7133 * address, but Remove Device allows only identity addresses.
7134 * Make sure it is enforced before calling
7135 * hci_conn_params_lookup.
7136 */
7137 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007138 err = mgmt_cmd_complete(sk, hdev->id,
7139 MGMT_OP_REMOVE_DEVICE,
7140 MGMT_STATUS_INVALID_PARAMS,
7141 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007142 goto unlock;
7143 }
7144
Johan Hedbergc71593d2014-07-02 17:37:28 +03007145 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7146 addr_type);
7147 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007148 err = mgmt_cmd_complete(sk, hdev->id,
7149 MGMT_OP_REMOVE_DEVICE,
7150 MGMT_STATUS_INVALID_PARAMS,
7151 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007152 goto unlock;
7153 }
7154
Johan Hedberg679d2b62015-10-16 10:07:52 +03007155 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
7156 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007157 err = mgmt_cmd_complete(sk, hdev->id,
7158 MGMT_OP_REMOVE_DEVICE,
7159 MGMT_STATUS_INVALID_PARAMS,
7160 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007161 goto unlock;
7162 }
7163
Johan Hedbergd1dbf122014-07-04 16:17:23 +03007164 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03007165 list_del(&params->list);
7166 kfree(params);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007167
7168 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007169 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03007170 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03007171 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03007172
Marcel Holtmann2faade52014-06-29 19:44:03 +02007173 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007174 err = mgmt_cmd_complete(sk, hdev->id,
7175 MGMT_OP_REMOVE_DEVICE,
7176 MGMT_STATUS_INVALID_PARAMS,
7177 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007178 goto unlock;
7179 }
7180
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007181 list_for_each_entry_safe(b, btmp, &hdev->accept_list, list) {
Johan Hedberg66593582014-07-09 12:59:14 +03007182 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
7183 list_del(&b->list);
7184 kfree(b);
7185 }
7186
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007187 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007188
Johan Hedberg19de0822014-07-06 13:06:51 +03007189 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
7190 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
7191 continue;
7192 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03007193 if (p->explicit_connect) {
7194 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
7195 continue;
7196 }
Johan Hedberg19de0822014-07-06 13:06:51 +03007197 list_del(&p->action);
7198 list_del(&p->list);
7199 kfree(p);
7200 }
7201
Marcel Holtmann181d6952020-05-06 09:57:47 +02007202 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Marcel Holtmann2faade52014-06-29 19:44:03 +02007203 }
7204
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007205 hci_cmd_sync_queue(hdev, remove_device_sync, NULL, NULL);
7206
Johan Hedberg66593582014-07-09 12:59:14 +03007207complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02007208 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
7209 MGMT_STATUS_SUCCESS, &cp->addr,
7210 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007211unlock:
7212 hci_dev_unlock(hdev);
7213 return err;
7214}
7215
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007216static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
7217 u16 len)
7218{
7219 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03007220 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
7221 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007222 u16 param_count, expected_len;
7223 int i;
7224
7225 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007226 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7227 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007228
7229 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007230 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007231 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
7232 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02007233 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7234 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007235 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007236
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05007237 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007238 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007239 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
7240 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02007241 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7242 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007243 }
7244
Marcel Holtmann181d6952020-05-06 09:57:47 +02007245 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007246
7247 hci_dev_lock(hdev);
7248
7249 hci_conn_params_clear_disabled(hdev);
7250
7251 for (i = 0; i < param_count; i++) {
7252 struct mgmt_conn_param *param = &cp->params[i];
7253 struct hci_conn_params *hci_param;
7254 u16 min, max, latency, timeout;
7255 u8 addr_type;
7256
Marcel Holtmann181d6952020-05-06 09:57:47 +02007257 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
7258 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007259
7260 if (param->addr.type == BDADDR_LE_PUBLIC) {
7261 addr_type = ADDR_LE_DEV_PUBLIC;
7262 } else if (param->addr.type == BDADDR_LE_RANDOM) {
7263 addr_type = ADDR_LE_DEV_RANDOM;
7264 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007265 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007266 continue;
7267 }
7268
7269 min = le16_to_cpu(param->min_interval);
7270 max = le16_to_cpu(param->max_interval);
7271 latency = le16_to_cpu(param->latency);
7272 timeout = le16_to_cpu(param->timeout);
7273
Marcel Holtmann181d6952020-05-06 09:57:47 +02007274 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
7275 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007276
7277 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007278 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007279 continue;
7280 }
7281
7282 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
7283 addr_type);
7284 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007285 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007286 continue;
7287 }
7288
7289 hci_param->conn_min_interval = min;
7290 hci_param->conn_max_interval = max;
7291 hci_param->conn_latency = latency;
7292 hci_param->supervision_timeout = timeout;
7293 }
7294
7295 hci_dev_unlock(hdev);
7296
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007297 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
7298 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007299}
7300
Marcel Holtmanndbece372014-07-04 18:11:55 +02007301static int set_external_config(struct sock *sk, struct hci_dev *hdev,
7302 void *data, u16 len)
7303{
7304 struct mgmt_cp_set_external_config *cp = data;
7305 bool changed;
7306 int err;
7307
Marcel Holtmann181d6952020-05-06 09:57:47 +02007308 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007309
7310 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007311 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7312 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007313
7314 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02007315 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7316 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007317
7318 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02007319 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7320 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007321
7322 hci_dev_lock(hdev);
7323
7324 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07007325 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007326 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007327 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007328
7329 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
7330 if (err < 0)
7331 goto unlock;
7332
7333 if (!changed)
7334 goto unlock;
7335
Marcel Holtmannf4537c02014-07-04 19:06:23 +02007336 err = new_options(hdev, sk);
7337
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007338 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02007339 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007340
Marcel Holtmann516018a2015-03-13 02:11:04 -07007341 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007342 hci_dev_set_flag(hdev, HCI_CONFIG);
7343 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007344
7345 queue_work(hdev->req_workqueue, &hdev->power_on);
7346 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02007347 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007348 mgmt_index_added(hdev);
7349 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02007350 }
7351
7352unlock:
7353 hci_dev_unlock(hdev);
7354 return err;
7355}
7356
Marcel Holtmann9713c172014-07-06 12:11:15 +02007357static int set_public_address(struct sock *sk, struct hci_dev *hdev,
7358 void *data, u16 len)
7359{
7360 struct mgmt_cp_set_public_address *cp = data;
7361 bool changed;
7362 int err;
7363
Marcel Holtmann181d6952020-05-06 09:57:47 +02007364 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007365
7366 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007367 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7368 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007369
7370 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02007371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7372 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007373
7374 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02007375 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7376 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007377
7378 hci_dev_lock(hdev);
7379
7380 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
7381 bacpy(&hdev->public_addr, &cp->bdaddr);
7382
7383 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
7384 if (err < 0)
7385 goto unlock;
7386
7387 if (!changed)
7388 goto unlock;
7389
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007390 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02007391 err = new_options(hdev, sk);
7392
7393 if (is_configured(hdev)) {
7394 mgmt_index_removed(hdev);
7395
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007396 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007397
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007398 hci_dev_set_flag(hdev, HCI_CONFIG);
7399 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007400
7401 queue_work(hdev->req_workqueue, &hdev->power_on);
7402 }
7403
7404unlock:
7405 hci_dev_unlock(hdev);
7406 return err;
7407}
7408
Brian Gix177e77a2021-10-27 16:58:53 -07007409static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
7410 int err)
Johan Hedberg40f66c02015-04-07 21:52:22 +03007411{
7412 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
7413 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
7414 u8 *h192, *r192, *h256, *r256;
Brian Gix177e77a2021-10-27 16:58:53 -07007415 struct mgmt_pending_cmd *cmd = data;
7416 struct sk_buff *skb = cmd->skb;
7417 u8 status = mgmt_status(err);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007418 u16 eir_len;
Brian Gix177e77a2021-10-27 16:58:53 -07007419
7420 if (!status) {
7421 if (!skb)
7422 status = MGMT_STATUS_FAILED;
7423 else if (IS_ERR(skb))
7424 status = mgmt_status(PTR_ERR(skb));
7425 else
7426 status = mgmt_status(skb->data[0]);
7427 }
Johan Hedberg40f66c02015-04-07 21:52:22 +03007428
Marcel Holtmann181d6952020-05-06 09:57:47 +02007429 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007430
Johan Hedberg40f66c02015-04-07 21:52:22 +03007431 mgmt_cp = cmd->param;
7432
7433 if (status) {
7434 status = mgmt_status(status);
7435 eir_len = 0;
7436
7437 h192 = NULL;
7438 r192 = NULL;
7439 h256 = NULL;
7440 r256 = NULL;
Brian Gix177e77a2021-10-27 16:58:53 -07007441 } else if (!bredr_sc_enabled(hdev)) {
Johan Hedberg40f66c02015-04-07 21:52:22 +03007442 struct hci_rp_read_local_oob_data *rp;
7443
7444 if (skb->len != sizeof(*rp)) {
7445 status = MGMT_STATUS_FAILED;
7446 eir_len = 0;
7447 } else {
7448 status = MGMT_STATUS_SUCCESS;
7449 rp = (void *)skb->data;
7450
7451 eir_len = 5 + 18 + 18;
7452 h192 = rp->hash;
7453 r192 = rp->rand;
7454 h256 = NULL;
7455 r256 = NULL;
7456 }
7457 } else {
7458 struct hci_rp_read_local_oob_ext_data *rp;
7459
7460 if (skb->len != sizeof(*rp)) {
7461 status = MGMT_STATUS_FAILED;
7462 eir_len = 0;
7463 } else {
7464 status = MGMT_STATUS_SUCCESS;
7465 rp = (void *)skb->data;
7466
7467 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
7468 eir_len = 5 + 18 + 18;
7469 h192 = NULL;
7470 r192 = NULL;
7471 } else {
7472 eir_len = 5 + 18 + 18 + 18 + 18;
7473 h192 = rp->hash192;
7474 r192 = rp->rand192;
7475 }
7476
7477 h256 = rp->hash256;
7478 r256 = rp->rand256;
7479 }
7480 }
7481
7482 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
7483 if (!mgmt_rp)
7484 goto done;
7485
Kees Cooka31e5a42021-08-17 21:39:12 -07007486 if (eir_len == 0)
Johan Hedberg40f66c02015-04-07 21:52:22 +03007487 goto send_rsp;
7488
7489 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
7490 hdev->dev_class, 3);
7491
7492 if (h192 && r192) {
7493 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7494 EIR_SSP_HASH_C192, h192, 16);
7495 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7496 EIR_SSP_RAND_R192, r192, 16);
7497 }
7498
7499 if (h256 && r256) {
7500 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7501 EIR_SSP_HASH_C256, h256, 16);
7502 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7503 EIR_SSP_RAND_R256, r256, 16);
7504 }
7505
7506send_rsp:
7507 mgmt_rp->type = mgmt_cp->type;
7508 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7509
7510 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7511 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7512 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7513 if (err < 0 || status)
7514 goto done;
7515
7516 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7517
7518 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7519 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7520 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7521done:
Brian Gix177e77a2021-10-27 16:58:53 -07007522 if (skb && !IS_ERR(skb))
7523 kfree_skb(skb);
7524
Johan Hedberg40f66c02015-04-07 21:52:22 +03007525 kfree(mgmt_rp);
7526 mgmt_pending_remove(cmd);
7527}
7528
7529static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7530 struct mgmt_cp_read_local_oob_ext_data *cp)
7531{
7532 struct mgmt_pending_cmd *cmd;
Johan Hedberg40f66c02015-04-07 21:52:22 +03007533 int err;
7534
7535 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7536 cp, sizeof(*cp));
7537 if (!cmd)
7538 return -ENOMEM;
7539
Brian Gix177e77a2021-10-27 16:58:53 -07007540 err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
7541 read_local_oob_ext_data_complete);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007542
Johan Hedberg40f66c02015-04-07 21:52:22 +03007543 if (err < 0) {
7544 mgmt_pending_remove(cmd);
7545 return err;
7546 }
7547
7548 return 0;
7549}
7550
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007551static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7552 void *data, u16 data_len)
7553{
7554 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7555 struct mgmt_rp_read_local_oob_ext_data *rp;
7556 size_t rp_len;
7557 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007558 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007559 int err;
7560
Marcel Holtmann181d6952020-05-06 09:57:47 +02007561 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007562
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007563 if (hdev_is_powered(hdev)) {
7564 switch (cp->type) {
7565 case BIT(BDADDR_BREDR):
7566 status = mgmt_bredr_support(hdev);
7567 if (status)
7568 eir_len = 0;
7569 else
7570 eir_len = 5;
7571 break;
7572 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7573 status = mgmt_le_support(hdev);
7574 if (status)
7575 eir_len = 0;
7576 else
7577 eir_len = 9 + 3 + 18 + 18 + 3;
7578 break;
7579 default:
7580 status = MGMT_STATUS_INVALID_PARAMS;
7581 eir_len = 0;
7582 break;
7583 }
7584 } else {
7585 status = MGMT_STATUS_NOT_POWERED;
7586 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007587 }
7588
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007589 rp_len = sizeof(*rp) + eir_len;
7590 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007591 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007592 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007593
Brian Gix81218cb2021-08-23 14:57:29 -07007594 if (!status && !lmp_ssp_capable(hdev)) {
7595 status = MGMT_STATUS_NOT_SUPPORTED;
7596 eir_len = 0;
7597 }
7598
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007599 if (status)
7600 goto complete;
7601
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007602 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007603
7604 eir_len = 0;
7605 switch (cp->type) {
7606 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007607 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7608 err = read_local_ssp_oob_req(hdev, sk, cp);
7609 hci_dev_unlock(hdev);
7610 if (!err)
7611 goto done;
7612
7613 status = MGMT_STATUS_FAILED;
7614 goto complete;
7615 } else {
7616 eir_len = eir_append_data(rp->eir, eir_len,
7617 EIR_CLASS_OF_DEV,
7618 hdev->dev_class, 3);
7619 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007620 break;
7621 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007622 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7623 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007624 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007625 status = MGMT_STATUS_FAILED;
7626 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007627 }
7628
Marcel Holtmanne2135682015-04-02 12:00:58 -07007629 /* This should return the active RPA, but since the RPA
7630 * is only programmed on demand, it is really hard to fill
7631 * this in at the moment. For now disallow retrieving
7632 * local out-of-band data when privacy is in use.
7633 *
7634 * Returning the identity address will not help here since
7635 * pairing happens before the identity resolving key is
7636 * known and thus the connection establishment happens
7637 * based on the RPA and not the identity address.
7638 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007639 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007640 hci_dev_unlock(hdev);
7641 status = MGMT_STATUS_REJECTED;
7642 goto complete;
7643 }
7644
7645 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7646 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7647 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7648 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007649 memcpy(addr, &hdev->static_addr, 6);
7650 addr[6] = 0x01;
7651 } else {
7652 memcpy(addr, &hdev->bdaddr, 6);
7653 addr[6] = 0x00;
7654 }
7655
7656 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7657 addr, sizeof(addr));
7658
7659 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7660 role = 0x02;
7661 else
7662 role = 0x01;
7663
7664 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7665 &role, sizeof(role));
7666
Marcel Holtmann5082a592015-03-16 12:39:00 -07007667 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7668 eir_len = eir_append_data(rp->eir, eir_len,
7669 EIR_LE_SC_CONFIRM,
7670 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007671
Marcel Holtmann5082a592015-03-16 12:39:00 -07007672 eir_len = eir_append_data(rp->eir, eir_len,
7673 EIR_LE_SC_RANDOM,
7674 rand, sizeof(rand));
7675 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007676
Johan Hedbergf2252572015-11-18 12:49:20 +02007677 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007678
7679 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7680 flags |= LE_AD_NO_BREDR;
7681
7682 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7683 &flags, sizeof(flags));
7684 break;
7685 }
7686
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007687 hci_dev_unlock(hdev);
7688
Marcel Holtmann72000df2015-03-16 16:11:21 -07007689 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7690
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007691 status = MGMT_STATUS_SUCCESS;
7692
7693complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007694 rp->type = cp->type;
7695 rp->eir_len = cpu_to_le16(eir_len);
7696
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007697 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007698 status, rp, sizeof(*rp) + eir_len);
7699 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007700 goto done;
7701
7702 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7703 rp, sizeof(*rp) + eir_len,
7704 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007705
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007706done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007707 kfree(rp);
7708
7709 return err;
7710}
7711
Arman Uguray089fa8c2015-03-25 18:53:45 -07007712static u32 get_supported_adv_flags(struct hci_dev *hdev)
7713{
7714 u32 flags = 0;
7715
7716 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7717 flags |= MGMT_ADV_FLAG_DISCOV;
7718 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7719 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007720 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007721 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Daniel Winkler12410572020-12-03 12:12:49 -08007722 flags |= MGMT_ADV_PARAM_DURATION;
7723 flags |= MGMT_ADV_PARAM_TIMEOUT;
7724 flags |= MGMT_ADV_PARAM_INTERVALS;
7725 flags |= MGMT_ADV_PARAM_TX_POWER;
Daniel Winklerff02db12021-03-03 11:15:23 -08007726 flags |= MGMT_ADV_PARAM_SCAN_RSP;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007727
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307728 /* In extended adv TX_POWER returned from Set Adv Param
7729 * will be always valid.
7730 */
7731 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7732 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007733 flags |= MGMT_ADV_FLAG_TX_POWER;
7734
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307735 if (ext_adv_capable(hdev)) {
7736 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007737 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7738 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307739
7740 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7741 flags |= MGMT_ADV_FLAG_SEC_2M;
7742
7743 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7744 flags |= MGMT_ADV_FLAG_SEC_CODED;
7745 }
7746
Arman Uguray089fa8c2015-03-25 18:53:45 -07007747 return flags;
7748}
7749
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007750static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7751 void *data, u16 data_len)
7752{
7753 struct mgmt_rp_read_adv_features *rp;
7754 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007755 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007756 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007757 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007758 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007759
Marcel Holtmann181d6952020-05-06 09:57:47 +02007760 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007761
Arman Uguray089fa8c2015-03-25 18:53:45 -07007762 if (!lmp_le_capable(hdev))
7763 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7764 MGMT_STATUS_REJECTED);
7765
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007766 hci_dev_lock(hdev);
7767
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007768 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007769 rp = kmalloc(rp_len, GFP_ATOMIC);
7770 if (!rp) {
7771 hci_dev_unlock(hdev);
7772 return -ENOMEM;
7773 }
7774
Arman Uguray089fa8c2015-03-25 18:53:45 -07007775 supported_flags = get_supported_adv_flags(hdev);
7776
7777 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007778 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7779 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007780 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007781 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007782
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007783 instance = rp->instance;
7784 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7785 *instance = adv_instance->instance;
7786 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007787 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007788
7789 hci_dev_unlock(hdev);
7790
7791 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7792 MGMT_STATUS_SUCCESS, rp, rp_len);
7793
7794 kfree(rp);
7795
7796 return err;
7797}
7798
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007799static u8 calculate_name_len(struct hci_dev *hdev)
7800{
7801 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7802
Luiz Augusto von Dentz01ce70b2021-09-20 15:59:37 -07007803 return eir_append_local_name(hdev, buf, 0);
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007804}
7805
7806static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7807 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007808{
Arman Uguray4117ed72015-03-23 15:57:14 -07007809 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007810
Marcel Holtmann31a32482015-11-19 16:16:42 +01007811 if (is_adv_data) {
7812 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7813 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007814 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007815 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007816
Szymon Janc2bb368702016-09-18 12:50:05 +02007817 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007818 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007819 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007820 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007821 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007822
Szymon Janc2bb368702016-09-18 12:50:05 +02007823 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007824 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007825 }
7826
Szymon Janc2bb368702016-09-18 12:50:05 +02007827 return max_len;
7828}
7829
7830static bool flags_managed(u32 adv_flags)
7831{
7832 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7833 MGMT_ADV_FLAG_LIMITED_DISCOV |
7834 MGMT_ADV_FLAG_MANAGED_FLAGS);
7835}
7836
7837static bool tx_power_managed(u32 adv_flags)
7838{
7839 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7840}
7841
7842static bool name_managed(u32 adv_flags)
7843{
7844 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7845}
7846
7847static bool appearance_managed(u32 adv_flags)
7848{
7849 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7850}
7851
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007852static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7853 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007854{
7855 int i, cur_len;
7856 u8 max_len;
7857
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007858 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007859
Arman Uguray4117ed72015-03-23 15:57:14 -07007860 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007861 return false;
7862
Arman Uguray4117ed72015-03-23 15:57:14 -07007863 /* Make sure that the data is correctly formatted. */
7864 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7865 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007866
Luiz Augusto von Dentz799acb92021-05-28 11:45:02 -07007867 if (!cur_len)
7868 continue;
7869
Szymon Janc9c9db782016-09-18 12:50:06 +02007870 if (data[i + 1] == EIR_FLAGS &&
7871 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007872 return false;
7873
Szymon Janc2bb368702016-09-18 12:50:05 +02007874 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7875 return false;
7876
7877 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7878 return false;
7879
7880 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7881 return false;
7882
7883 if (data[i + 1] == EIR_APPEARANCE &&
7884 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007885 return false;
7886
Arman Uguray24b4f382015-03-23 15:57:12 -07007887 /* If the current field length would exceed the total data
7888 * length, then it's invalid.
7889 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007890 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007891 return false;
7892 }
7893
7894 return true;
7895}
7896
Daniel Winkler12410572020-12-03 12:12:49 -08007897static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
7898{
7899 u32 supported_flags, phy_flags;
7900
7901 /* The current implementation only supports a subset of the specified
7902 * flags. Also need to check mutual exclusiveness of sec flags.
7903 */
7904 supported_flags = get_supported_adv_flags(hdev);
7905 phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK;
7906 if (adv_flags & ~supported_flags ||
7907 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
7908 return false;
7909
7910 return true;
7911}
7912
7913static bool adv_busy(struct hci_dev *hdev)
7914{
7915 return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7916 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7917 pending_find(MGMT_OP_SET_LE, hdev) ||
7918 pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
7919 pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
7920}
7921
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007922static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
7923 int err)
Arman Uguray24b4f382015-03-23 15:57:12 -07007924{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007925 struct adv_info *adv, *n;
Arman Uguray24b4f382015-03-23 15:57:12 -07007926
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007927 bt_dev_dbg(hdev, "err %d", err);
Arman Uguray24b4f382015-03-23 15:57:12 -07007928
7929 hci_dev_lock(hdev);
7930
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007931 list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
7932 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007933
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007934 if (!adv->pending)
Florian Grandelfffd38b2015-06-18 03:16:47 +02007935 continue;
7936
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007937 if (!err) {
7938 adv->pending = false;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007939 continue;
7940 }
7941
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007942 instance = adv->instance;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007943
7944 if (hdev->cur_adv_instance == instance)
7945 cancel_adv_timeout(hdev);
7946
7947 hci_remove_adv_instance(hdev, instance);
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007948 mgmt_advertising_removed(sk, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007949 }
7950
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007951 hci_dev_unlock(hdev);
7952}
Arman Uguray24b4f382015-03-23 15:57:12 -07007953
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007954static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
7955{
7956 struct mgmt_pending_cmd *cmd = data;
7957 struct mgmt_cp_add_advertising *cp = cmd->param;
7958 struct mgmt_rp_add_advertising rp;
7959
7960 memset(&rp, 0, sizeof(rp));
7961
Florian Grandelfffd38b2015-06-18 03:16:47 +02007962 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007963
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007964 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07007965 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007966 mgmt_status(err));
Arman Uguray24b4f382015-03-23 15:57:12 -07007967 else
7968 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007969 mgmt_status(err), &rp, sizeof(rp));
Arman Uguray24b4f382015-03-23 15:57:12 -07007970
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007971 add_adv_complete(hdev, cmd->sk, cp->instance, err);
Arman Uguray24b4f382015-03-23 15:57:12 -07007972
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007973 mgmt_pending_free(cmd);
7974}
7975
7976static int add_advertising_sync(struct hci_dev *hdev, void *data)
7977{
7978 struct mgmt_pending_cmd *cmd = data;
7979 struct mgmt_cp_add_advertising *cp = cmd->param;
7980
7981 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007982}
7983
7984static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7985 void *data, u16 data_len)
7986{
7987 struct mgmt_cp_add_advertising *cp = data;
7988 struct mgmt_rp_add_advertising rp;
7989 u32 flags;
7990 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007991 u16 timeout, duration;
7992 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7993 u8 schedule_instance = 0;
7994 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007995 int err;
7996 struct mgmt_pending_cmd *cmd;
Arman Uguray24b4f382015-03-23 15:57:12 -07007997
Marcel Holtmann181d6952020-05-06 09:57:47 +02007998 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007999
8000 status = mgmt_le_support(hdev);
8001 if (status)
8002 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8003 status);
8004
Daniel Winkler87597482020-08-25 16:31:50 -07008005 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01008006 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8007 MGMT_STATUS_INVALID_PARAMS);
8008
Johan Hedberg6a0e7802016-03-11 09:56:33 +02008009 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
8010 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8011 MGMT_STATUS_INVALID_PARAMS);
8012
Arman Uguray24b4f382015-03-23 15:57:12 -07008013 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07008014 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008015 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07008016
Daniel Winkler12410572020-12-03 12:12:49 -08008017 if (!requested_adv_flags_are_valid(hdev, flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07008018 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8019 MGMT_STATUS_INVALID_PARAMS);
8020
8021 hci_dev_lock(hdev);
8022
Arman Uguray912098a2015-03-23 15:57:15 -07008023 if (timeout && !hdev_is_powered(hdev)) {
8024 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8025 MGMT_STATUS_REJECTED);
8026 goto unlock;
8027 }
8028
Daniel Winkler12410572020-12-03 12:12:49 -08008029 if (adv_busy(hdev)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008030 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8031 MGMT_STATUS_BUSY);
8032 goto unlock;
8033 }
8034
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008035 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
8036 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07008037 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008038 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8039 MGMT_STATUS_INVALID_PARAMS);
8040 goto unlock;
8041 }
8042
Florian Grandelfffd38b2015-06-18 03:16:47 +02008043 err = hci_add_adv_instance(hdev, cp->instance, flags,
8044 cp->adv_data_len, cp->data,
8045 cp->scan_rsp_len,
8046 cp->data + cp->adv_data_len,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008047 timeout, duration,
8048 HCI_ADV_TX_POWER_NO_PREFERENCE,
8049 hdev->le_adv_min_interval,
8050 hdev->le_adv_max_interval);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008051 if (err < 0) {
8052 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8053 MGMT_STATUS_FAILED);
8054 goto unlock;
8055 }
Arman Uguray24b4f382015-03-23 15:57:12 -07008056
Florian Grandelfffd38b2015-06-18 03:16:47 +02008057 /* Only trigger an advertising added event if a new instance was
8058 * actually added.
8059 */
8060 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02008061 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07008062
Florian Grandelfffd38b2015-06-18 03:16:47 +02008063 if (hdev->cur_adv_instance == cp->instance) {
8064 /* If the currently advertised instance is being changed then
8065 * cancel the current advertising and schedule the next
8066 * instance. If there is only one instance then the overridden
8067 * advertising data will be visible right away.
8068 */
8069 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07008070
Florian Grandelfffd38b2015-06-18 03:16:47 +02008071 next_instance = hci_get_next_instance(hdev, cp->instance);
8072 if (next_instance)
8073 schedule_instance = next_instance->instance;
8074 } else if (!hdev->adv_instance_timeout) {
8075 /* Immediately advertise the new instance if no other
8076 * instance is currently being advertised.
8077 */
8078 schedule_instance = cp->instance;
8079 }
Arman Uguray912098a2015-03-23 15:57:15 -07008080
Florian Grandelfffd38b2015-06-18 03:16:47 +02008081 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
8082 * there is no instance to be advertised then we have no HCI
8083 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07008084 */
8085 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02008086 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
8087 !schedule_instance) {
8088 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008089 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8090 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8091 goto unlock;
8092 }
8093
8094 /* We're good to go, update advertising data, parameters, and start
8095 * advertising.
8096 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008097 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
Arman Uguray24b4f382015-03-23 15:57:12 -07008098 data_len);
8099 if (!cmd) {
8100 err = -ENOMEM;
8101 goto unlock;
8102 }
8103
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008104 cp->instance = schedule_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008105
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008106 err = hci_cmd_sync_queue(hdev, add_advertising_sync, cmd,
8107 add_advertising_complete);
8108 if (err < 0)
8109 mgmt_pending_free(cmd);
Arman Uguray24b4f382015-03-23 15:57:12 -07008110
8111unlock:
8112 hci_dev_unlock(hdev);
8113
8114 return err;
8115}
8116
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008117static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
8118 int err)
Daniel Winkler12410572020-12-03 12:12:49 -08008119{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008120 struct mgmt_pending_cmd *cmd = data;
8121 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
Daniel Winkler12410572020-12-03 12:12:49 -08008122 struct mgmt_rp_add_ext_adv_params rp;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008123 struct adv_info *adv;
Daniel Winkler12410572020-12-03 12:12:49 -08008124 u32 flags;
8125
8126 BT_DBG("%s", hdev->name);
8127
8128 hci_dev_lock(hdev);
8129
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008130 adv = hci_find_adv_instance(hdev, cp->instance);
8131 if (!adv)
Daniel Winkler12410572020-12-03 12:12:49 -08008132 goto unlock;
8133
8134 rp.instance = cp->instance;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008135 rp.tx_power = adv->tx_power;
Daniel Winkler12410572020-12-03 12:12:49 -08008136
8137 /* While we're at it, inform userspace of the available space for this
8138 * advertisement, given the flags that will be used.
8139 */
8140 flags = __le32_to_cpu(cp->flags);
8141 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8142 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8143
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008144 if (err) {
Daniel Winkler12410572020-12-03 12:12:49 -08008145 /* If this advertisement was previously advertising and we
8146 * failed to update it, we signal that it has been removed and
8147 * delete its structure
8148 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008149 if (!adv->pending)
Daniel Winkler12410572020-12-03 12:12:49 -08008150 mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
8151
8152 hci_remove_adv_instance(hdev, cp->instance);
8153
8154 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008155 mgmt_status(err));
Daniel Winkler12410572020-12-03 12:12:49 -08008156 } else {
8157 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008158 mgmt_status(err), &rp, sizeof(rp));
Daniel Winkler12410572020-12-03 12:12:49 -08008159 }
8160
8161unlock:
8162 if (cmd)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008163 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008164
8165 hci_dev_unlock(hdev);
8166}
8167
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008168static int add_ext_adv_params_sync(struct hci_dev *hdev, void *data)
8169{
8170 struct mgmt_pending_cmd *cmd = data;
8171 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
8172
8173 return hci_setup_ext_adv_instance_sync(hdev, cp->instance);
8174}
8175
Daniel Winkler12410572020-12-03 12:12:49 -08008176static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
8177 void *data, u16 data_len)
8178{
8179 struct mgmt_cp_add_ext_adv_params *cp = data;
8180 struct mgmt_rp_add_ext_adv_params rp;
8181 struct mgmt_pending_cmd *cmd = NULL;
Daniel Winkler12410572020-12-03 12:12:49 -08008182 u32 flags, min_interval, max_interval;
8183 u16 timeout, duration;
8184 u8 status;
8185 s8 tx_power;
8186 int err;
8187
8188 BT_DBG("%s", hdev->name);
8189
8190 status = mgmt_le_support(hdev);
8191 if (status)
8192 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8193 status);
8194
8195 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
8196 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8197 MGMT_STATUS_INVALID_PARAMS);
8198
8199 /* The purpose of breaking add_advertising into two separate MGMT calls
8200 * for params and data is to allow more parameters to be added to this
8201 * structure in the future. For this reason, we verify that we have the
8202 * bare minimum structure we know of when the interface was defined. Any
8203 * extra parameters we don't know about will be ignored in this request.
8204 */
8205 if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE)
8206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8207 MGMT_STATUS_INVALID_PARAMS);
8208
8209 flags = __le32_to_cpu(cp->flags);
8210
8211 if (!requested_adv_flags_are_valid(hdev, flags))
8212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8213 MGMT_STATUS_INVALID_PARAMS);
8214
8215 hci_dev_lock(hdev);
8216
8217 /* In new interface, we require that we are powered to register */
8218 if (!hdev_is_powered(hdev)) {
8219 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8220 MGMT_STATUS_REJECTED);
8221 goto unlock;
8222 }
8223
8224 if (adv_busy(hdev)) {
8225 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8226 MGMT_STATUS_BUSY);
8227 goto unlock;
8228 }
8229
8230 /* Parse defined parameters from request, use defaults otherwise */
8231 timeout = (flags & MGMT_ADV_PARAM_TIMEOUT) ?
8232 __le16_to_cpu(cp->timeout) : 0;
8233
8234 duration = (flags & MGMT_ADV_PARAM_DURATION) ?
8235 __le16_to_cpu(cp->duration) :
8236 hdev->def_multi_adv_rotation_duration;
8237
8238 min_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8239 __le32_to_cpu(cp->min_interval) :
8240 hdev->le_adv_min_interval;
8241
8242 max_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8243 __le32_to_cpu(cp->max_interval) :
8244 hdev->le_adv_max_interval;
8245
8246 tx_power = (flags & MGMT_ADV_PARAM_TX_POWER) ?
8247 cp->tx_power :
8248 HCI_ADV_TX_POWER_NO_PREFERENCE;
8249
8250 /* Create advertising instance with no advertising or response data */
8251 err = hci_add_adv_instance(hdev, cp->instance, flags,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008252 0, NULL, 0, NULL, timeout, duration,
8253 tx_power, min_interval, max_interval);
Daniel Winkler12410572020-12-03 12:12:49 -08008254
8255 if (err < 0) {
8256 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8257 MGMT_STATUS_FAILED);
8258 goto unlock;
8259 }
8260
Daniel Winkler12410572020-12-03 12:12:49 -08008261 /* Submit request for advertising params if ext adv available */
8262 if (ext_adv_capable(hdev)) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008263 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev,
8264 data, data_len);
Daniel Winkler12410572020-12-03 12:12:49 -08008265 if (!cmd) {
8266 err = -ENOMEM;
8267 hci_remove_adv_instance(hdev, cp->instance);
8268 goto unlock;
8269 }
8270
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008271 err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd,
8272 add_ext_adv_params_complete);
8273 if (err < 0)
8274 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008275 } else {
8276 rp.instance = cp->instance;
8277 rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
8278 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8279 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8280 err = mgmt_cmd_complete(sk, hdev->id,
8281 MGMT_OP_ADD_EXT_ADV_PARAMS,
8282 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8283 }
8284
8285unlock:
8286 hci_dev_unlock(hdev);
8287
8288 return err;
8289}
8290
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008291static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
8292{
8293 struct mgmt_pending_cmd *cmd = data;
8294 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8295 struct mgmt_rp_add_advertising rp;
8296
8297 add_adv_complete(hdev, cmd->sk, cp->instance, err);
8298
8299 memset(&rp, 0, sizeof(rp));
8300
8301 rp.instance = cp->instance;
8302
8303 if (err)
8304 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8305 mgmt_status(err));
8306 else
8307 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8308 mgmt_status(err), &rp, sizeof(rp));
8309
8310 mgmt_pending_free(cmd);
8311}
8312
8313static int add_ext_adv_data_sync(struct hci_dev *hdev, void *data)
8314{
8315 struct mgmt_pending_cmd *cmd = data;
8316 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8317 int err;
8318
8319 if (ext_adv_capable(hdev)) {
8320 err = hci_update_adv_data_sync(hdev, cp->instance);
8321 if (err)
8322 return err;
8323
8324 err = hci_update_scan_rsp_data_sync(hdev, cp->instance);
8325 if (err)
8326 return err;
8327
8328 return hci_enable_ext_advertising_sync(hdev, cp->instance);
8329 }
8330
8331 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
8332}
8333
Daniel Winkler12410572020-12-03 12:12:49 -08008334static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
8335 u16 data_len)
8336{
8337 struct mgmt_cp_add_ext_adv_data *cp = data;
8338 struct mgmt_rp_add_ext_adv_data rp;
8339 u8 schedule_instance = 0;
8340 struct adv_info *next_instance;
8341 struct adv_info *adv_instance;
8342 int err = 0;
8343 struct mgmt_pending_cmd *cmd;
Daniel Winkler12410572020-12-03 12:12:49 -08008344
8345 BT_DBG("%s", hdev->name);
8346
8347 hci_dev_lock(hdev);
8348
8349 adv_instance = hci_find_adv_instance(hdev, cp->instance);
8350
8351 if (!adv_instance) {
8352 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8353 MGMT_STATUS_INVALID_PARAMS);
8354 goto unlock;
8355 }
8356
8357 /* In new interface, we require that we are powered to register */
8358 if (!hdev_is_powered(hdev)) {
8359 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8360 MGMT_STATUS_REJECTED);
8361 goto clear_new_instance;
8362 }
8363
8364 if (adv_busy(hdev)) {
8365 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8366 MGMT_STATUS_BUSY);
8367 goto clear_new_instance;
8368 }
8369
8370 /* Validate new data */
8371 if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data,
8372 cp->adv_data_len, true) ||
8373 !tlv_data_is_valid(hdev, adv_instance->flags, cp->data +
8374 cp->adv_data_len, cp->scan_rsp_len, false)) {
8375 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8376 MGMT_STATUS_INVALID_PARAMS);
8377 goto clear_new_instance;
8378 }
8379
8380 /* Set the data in the advertising instance */
8381 hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len,
8382 cp->data, cp->scan_rsp_len,
8383 cp->data + cp->adv_data_len);
8384
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008385 /* If using software rotation, determine next instance to use */
8386 if (hdev->cur_adv_instance == cp->instance) {
8387 /* If the currently advertised instance is being changed
8388 * then cancel the current advertising and schedule the
8389 * next instance. If there is only one instance then the
8390 * overridden advertising data will be visible right
8391 * away
Daniel Winkler12410572020-12-03 12:12:49 -08008392 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008393 cancel_adv_timeout(hdev);
Daniel Winkler12410572020-12-03 12:12:49 -08008394
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008395 next_instance = hci_get_next_instance(hdev, cp->instance);
8396 if (next_instance)
8397 schedule_instance = next_instance->instance;
8398 } else if (!hdev->adv_instance_timeout) {
8399 /* Immediately advertise the new instance if no other
8400 * instance is currently being advertised.
8401 */
8402 schedule_instance = cp->instance;
Daniel Winkler12410572020-12-03 12:12:49 -08008403 }
8404
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008405 /* If the HCI_ADVERTISING flag is set or there is no instance to
8406 * be advertised then we have no HCI communication to make.
8407 * Simply return.
8408 */
8409 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) {
8410 if (adv_instance->pending) {
8411 mgmt_advertising_added(sk, hdev, cp->instance);
8412 adv_instance->pending = false;
8413 }
8414 rp.instance = cp->instance;
8415 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8416 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8417 goto unlock;
8418 }
8419
8420 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
Daniel Winkler12410572020-12-03 12:12:49 -08008421 data_len);
8422 if (!cmd) {
8423 err = -ENOMEM;
8424 goto clear_new_instance;
8425 }
8426
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008427 err = hci_cmd_sync_queue(hdev, add_ext_adv_data_sync, cmd,
8428 add_ext_adv_data_complete);
Daniel Winkler12410572020-12-03 12:12:49 -08008429 if (err < 0) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008430 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008431 goto clear_new_instance;
8432 }
8433
8434 /* We were successful in updating data, so trigger advertising_added
8435 * event if this is an instance that wasn't previously advertising. If
8436 * a failure occurs in the requests we initiated, we will remove the
8437 * instance again in add_advertising_complete
8438 */
8439 if (adv_instance->pending)
8440 mgmt_advertising_added(sk, hdev, cp->instance);
8441
8442 goto unlock;
8443
8444clear_new_instance:
8445 hci_remove_adv_instance(hdev, cp->instance);
8446
8447unlock:
8448 hci_dev_unlock(hdev);
8449
8450 return err;
8451}
8452
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008453static void remove_advertising_complete(struct hci_dev *hdev, void *data,
8454 int err)
Arman Ugurayda9293352015-03-23 15:57:13 -07008455{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008456 struct mgmt_pending_cmd *cmd = data;
8457 struct mgmt_cp_remove_advertising *cp = cmd->param;
Arman Ugurayda9293352015-03-23 15:57:13 -07008458 struct mgmt_rp_remove_advertising rp;
8459
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008460 bt_dev_dbg(hdev, "err %d", err);
Arman Ugurayda9293352015-03-23 15:57:13 -07008461
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008462 memset(&rp, 0, sizeof(rp));
Florian Grandel01948332015-06-18 03:16:48 +02008463 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008464
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008465 if (err)
8466 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8467 mgmt_status(err));
8468 else
8469 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8470 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Arman Ugurayda9293352015-03-23 15:57:13 -07008471
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008472 mgmt_pending_free(cmd);
8473}
8474
8475static int remove_advertising_sync(struct hci_dev *hdev, void *data)
8476{
8477 struct mgmt_pending_cmd *cmd = data;
8478 struct mgmt_cp_remove_advertising *cp = cmd->param;
8479 int err;
8480
8481 err = hci_remove_advertising_sync(hdev, cmd->sk, cp->instance, true);
8482 if (err)
8483 return err;
8484
8485 if (list_empty(&hdev->adv_instances))
8486 err = hci_disable_advertising_sync(hdev);
8487
8488 return err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008489}
8490
8491static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
8492 void *data, u16 data_len)
8493{
8494 struct mgmt_cp_remove_advertising *cp = data;
Arman Ugurayda9293352015-03-23 15:57:13 -07008495 struct mgmt_pending_cmd *cmd;
Johan Hedberg952497b2015-06-18 21:05:31 +03008496 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008497
Marcel Holtmann181d6952020-05-06 09:57:47 +02008498 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07008499
Arman Ugurayda9293352015-03-23 15:57:13 -07008500 hci_dev_lock(hdev);
8501
Johan Hedberg952497b2015-06-18 21:05:31 +03008502 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02008503 err = mgmt_cmd_status(sk, hdev->id,
8504 MGMT_OP_REMOVE_ADVERTISING,
8505 MGMT_STATUS_INVALID_PARAMS);
8506 goto unlock;
8507 }
8508
Arman Ugurayda9293352015-03-23 15:57:13 -07008509 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
8510 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
8511 pending_find(MGMT_OP_SET_LE, hdev)) {
8512 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8513 MGMT_STATUS_BUSY);
8514 goto unlock;
8515 }
8516
Johan Hedberg17fd08f2015-11-26 12:15:59 +02008517 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07008518 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8519 MGMT_STATUS_INVALID_PARAMS);
8520 goto unlock;
8521 }
8522
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008523 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
Arman Ugurayda9293352015-03-23 15:57:13 -07008524 data_len);
8525 if (!cmd) {
8526 err = -ENOMEM;
8527 goto unlock;
8528 }
8529
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008530 err = hci_cmd_sync_queue(hdev, remove_advertising_sync, cmd,
8531 remove_advertising_complete);
Arman Ugurayda9293352015-03-23 15:57:13 -07008532 if (err < 0)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008533 mgmt_pending_free(cmd);
Arman Ugurayda9293352015-03-23 15:57:13 -07008534
8535unlock:
8536 hci_dev_unlock(hdev);
8537
8538 return err;
8539}
8540
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008541static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
8542 void *data, u16 data_len)
8543{
8544 struct mgmt_cp_get_adv_size_info *cp = data;
8545 struct mgmt_rp_get_adv_size_info rp;
8546 u32 flags, supported_flags;
8547 int err;
8548
Marcel Holtmann181d6952020-05-06 09:57:47 +02008549 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008550
8551 if (!lmp_le_capable(hdev))
8552 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8553 MGMT_STATUS_REJECTED);
8554
Daniel Winkler87597482020-08-25 16:31:50 -07008555 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8557 MGMT_STATUS_INVALID_PARAMS);
8558
8559 flags = __le32_to_cpu(cp->flags);
8560
8561 /* The current implementation only supports a subset of the specified
8562 * flags.
8563 */
8564 supported_flags = get_supported_adv_flags(hdev);
8565 if (flags & ~supported_flags)
8566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8567 MGMT_STATUS_INVALID_PARAMS);
8568
8569 rp.instance = cp->instance;
8570 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008571 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8572 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008573
8574 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8575 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8576
8577 return err;
8578}
8579
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008580static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008581 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008582 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008583 HCI_MGMT_NO_HDEV |
8584 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008585 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008586 HCI_MGMT_NO_HDEV |
8587 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008588 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008589 HCI_MGMT_NO_HDEV |
8590 HCI_MGMT_UNTRUSTED },
8591 { read_controller_info, MGMT_READ_INFO_SIZE,
8592 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008593 { set_powered, MGMT_SETTING_SIZE },
8594 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
8595 { set_connectable, MGMT_SETTING_SIZE },
8596 { set_fast_connectable, MGMT_SETTING_SIZE },
8597 { set_bondable, MGMT_SETTING_SIZE },
8598 { set_link_security, MGMT_SETTING_SIZE },
8599 { set_ssp, MGMT_SETTING_SIZE },
8600 { set_hs, MGMT_SETTING_SIZE },
8601 { set_le, MGMT_SETTING_SIZE },
8602 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
8603 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
8604 { add_uuid, MGMT_ADD_UUID_SIZE },
8605 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008606 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
8607 HCI_MGMT_VAR_LEN },
8608 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
8609 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008610 { disconnect, MGMT_DISCONNECT_SIZE },
8611 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
8612 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
8613 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
8614 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
8615 { pair_device, MGMT_PAIR_DEVICE_SIZE },
8616 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
8617 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
8618 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
8619 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
8620 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
8621 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008622 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
8623 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
8624 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008625 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
8626 { start_discovery, MGMT_START_DISCOVERY_SIZE },
8627 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
8628 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
8629 { block_device, MGMT_BLOCK_DEVICE_SIZE },
8630 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
8631 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
8632 { set_advertising, MGMT_SETTING_SIZE },
8633 { set_bredr, MGMT_SETTING_SIZE },
8634 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
8635 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
8636 { set_secure_conn, MGMT_SETTING_SIZE },
8637 { set_debug_keys, MGMT_SETTING_SIZE },
8638 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008639 { load_irks, MGMT_LOAD_IRKS_SIZE,
8640 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008641 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
8642 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
8643 { add_device, MGMT_ADD_DEVICE_SIZE },
8644 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008645 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
8646 HCI_MGMT_VAR_LEN },
8647 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008648 HCI_MGMT_NO_HDEV |
8649 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008650 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008651 HCI_MGMT_UNCONFIGURED |
8652 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008653 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
8654 HCI_MGMT_UNCONFIGURED },
8655 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
8656 HCI_MGMT_UNCONFIGURED },
8657 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
8658 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07008659 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07008660 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008661 HCI_MGMT_NO_HDEV |
8662 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07008663 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07008664 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
8665 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07008666 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008667 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02008668 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008669 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
8670 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02008671 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05308672 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05308673 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00008674 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
8675 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00008676 { set_wideband_speech, MGMT_SETTING_SIZE },
Daniel Winkler4d9b9522020-12-03 12:12:52 -08008677 { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02008678 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02008679 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
8680 HCI_MGMT_UNTRUSTED |
8681 HCI_MGMT_HDEV_OPTIONAL },
8682 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
8683 HCI_MGMT_VAR_LEN |
8684 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00008685 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
8686 HCI_MGMT_UNTRUSTED },
8687 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
8688 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02008689 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
8690 HCI_MGMT_UNTRUSTED },
8691 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
8692 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02008693 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
8694 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02008695 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02008696 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
8697 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02008698 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Daniel Winkler12410572020-12-03 12:12:49 -08008699 { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE,
8700 HCI_MGMT_VAR_LEN },
8701 { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
8702 HCI_MGMT_VAR_LEN },
Archie Pusakab4a221e2021-01-22 16:36:11 +08008703 { add_adv_patterns_monitor_rssi,
8704 MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
8705 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008706};
8707
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008708void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008709{
Marcel Holtmannced85542015-03-14 19:27:56 -07008710 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03008711
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008712 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8713 return;
8714
Marcel Holtmannf9207332015-03-14 19:27:55 -07008715 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008716 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008717 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8718 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
8719 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008720 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008721 } else {
8722 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
8723 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008724 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008725 }
8726 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008727 case HCI_AMP:
8728 ev.type = 0x02;
8729 break;
8730 default:
8731 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008732 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008733
8734 ev.bus = hdev->bus;
8735
8736 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
8737 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008738}
8739
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008740void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008741{
Marcel Holtmannced85542015-03-14 19:27:56 -07008742 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02008743 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02008744
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008745 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8746 return;
8747
Marcel Holtmannf9207332015-03-14 19:27:55 -07008748 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008749 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008750 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02008751
Marcel Holtmannf9207332015-03-14 19:27:55 -07008752 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8753 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
8754 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008755 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008756 } else {
8757 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
8758 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008759 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008760 }
8761 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008762 case HCI_AMP:
8763 ev.type = 0x02;
8764 break;
8765 default:
8766 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008767 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008768
8769 ev.bus = hdev->bus;
8770
8771 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
8772 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008773}
8774
Johan Hedberg2ff13892015-11-25 16:15:44 +02008775void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05008776{
8777 struct cmd_lookup match = { NULL, hdev };
8778
Marcel Holtmann181d6952020-05-06 09:57:47 +02008779 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05008780
Johan Hedberg2ff13892015-11-25 16:15:44 +02008781 hci_dev_lock(hdev);
8782
8783 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008784 restart_le_actions(hdev);
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07008785 hci_update_passive_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08008786 }
8787
Johan Hedberg229ab392013-03-15 17:06:53 -05008788 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
8789
8790 new_settings(hdev, match.sk);
8791
Johan Hedberg229ab392013-03-15 17:06:53 -05008792 if (match.sk)
8793 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02008794
8795 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05008796}
8797
Johan Hedberg2ff13892015-11-25 16:15:44 +02008798void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02008799{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02008800 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02008801 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02008802
Johan Hedberg229ab392013-03-15 17:06:53 -05008803 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02008804
8805 /* If the power off is because of hdev unregistration let
8806 * use the appropriate INVALID_INDEX status. Otherwise use
8807 * NOT_POWERED. We cover both scenarios here since later in
8808 * mgmt_index_removed() any hci_conn callbacks will have already
8809 * been triggered, potentially causing misleading DISCONNECTED
8810 * status responses.
8811 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008812 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02008813 status = MGMT_STATUS_INVALID_INDEX;
8814 else
8815 status = MGMT_STATUS_NOT_POWERED;
8816
8817 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008818
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008819 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008820 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8821 zero_cod, sizeof(zero_cod),
8822 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008823 ext_info_changed(hdev, NULL);
8824 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008825
Johan Hedberg2ff13892015-11-25 16:15:44 +02008826 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008827
8828 if (match.sk)
8829 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008830}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008831
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008832void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008833{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008834 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008835 u8 status;
8836
Johan Hedberg333ae952015-03-17 13:48:47 +02008837 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008838 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008839 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008840
8841 if (err == -ERFKILL)
8842 status = MGMT_STATUS_RFKILLED;
8843 else
8844 status = MGMT_STATUS_FAILED;
8845
Johan Hedberga69e8372015-03-06 21:08:53 +02008846 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008847
8848 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008849}
8850
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008851void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8852 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008853{
Johan Hedberg86742e12011-11-07 23:13:38 +02008854 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008855
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008856 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008857
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008858 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008859 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008860 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008861 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008862 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008863 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008864
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008865 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008866}
Johan Hedbergf7520542011-01-20 12:34:39 +02008867
Johan Hedbergd7b25452014-05-23 13:19:53 +03008868static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8869{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008870 switch (ltk->type) {
8871 case SMP_LTK:
Archie Pusakafad646e2021-05-31 16:37:25 +08008872 case SMP_LTK_RESPONDER:
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008873 if (ltk->authenticated)
8874 return MGMT_LTK_AUTHENTICATED;
8875 return MGMT_LTK_UNAUTHENTICATED;
8876 case SMP_LTK_P256:
8877 if (ltk->authenticated)
8878 return MGMT_LTK_P256_AUTH;
8879 return MGMT_LTK_P256_UNAUTH;
8880 case SMP_LTK_P256_DEBUG:
8881 return MGMT_LTK_P256_DEBUG;
8882 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008883
8884 return MGMT_LTK_UNAUTHENTICATED;
8885}
8886
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008887void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008888{
8889 struct mgmt_ev_new_long_term_key ev;
8890
8891 memset(&ev, 0, sizeof(ev));
8892
Marcel Holtmann5192d302014-02-19 17:11:58 -08008893 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008894 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008895 * to store long term keys. Their addresses will change the
8896 * next time around.
8897 *
8898 * Only when a remote device provides an identity address
8899 * make sure the long term key is stored. If the remote
8900 * identity is known, the long term keys are internally
8901 * mapped to the identity address. So allow static random
8902 * and public addresses here.
8903 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008904 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8905 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8906 ev.store_hint = 0x00;
8907 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008908 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008909
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008910 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008911 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008912 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008913 ev.key.enc_size = key->enc_size;
8914 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008915 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008916
Johan Hedberg2ceba532014-06-16 19:25:16 +03008917 if (key->type == SMP_LTK)
Archie Pusakafad646e2021-05-31 16:37:25 +08008918 ev.key.initiator = 1;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008919
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008920 /* Make sure we copy only the significant bytes based on the
8921 * encryption key size, and set the rest of the value to zeroes.
8922 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008923 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008924 memset(ev.key.val + key->enc_size, 0,
8925 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008926
Marcel Holtmann083368f2013-10-15 14:26:29 -07008927 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008928}
8929
Johan Hedbergcad20c22015-10-12 13:36:19 +02008930void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008931{
8932 struct mgmt_ev_new_irk ev;
8933
8934 memset(&ev, 0, sizeof(ev));
8935
Johan Hedbergcad20c22015-10-12 13:36:19 +02008936 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008937
Johan Hedberg95fbac82014-02-19 15:18:31 +02008938 bacpy(&ev.rpa, &irk->rpa);
8939 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8940 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8941 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8942
8943 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8944}
8945
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008946void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8947 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008948{
8949 struct mgmt_ev_new_csrk ev;
8950
8951 memset(&ev, 0, sizeof(ev));
8952
8953 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008954 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008955 * to store signature resolving keys. Their addresses will change
8956 * the next time around.
8957 *
8958 * Only when a remote device provides an identity address
8959 * make sure the signature resolving key is stored. So allow
8960 * static random and public addresses here.
8961 */
8962 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8963 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8964 ev.store_hint = 0x00;
8965 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008966 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008967
8968 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8969 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008970 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008971 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8972
8973 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8974}
8975
Andre Guedesffb5a8272014-07-01 18:10:11 -03008976void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008977 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8978 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008979{
8980 struct mgmt_ev_new_conn_param ev;
8981
Johan Hedbergc103aea2014-07-02 17:37:34 +03008982 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8983 return;
8984
Andre Guedesffb5a8272014-07-01 18:10:11 -03008985 memset(&ev, 0, sizeof(ev));
8986 bacpy(&ev.addr.bdaddr, bdaddr);
8987 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008988 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008989 ev.min_interval = cpu_to_le16(min_interval);
8990 ev.max_interval = cpu_to_le16(max_interval);
8991 ev.latency = cpu_to_le16(latency);
8992 ev.timeout = cpu_to_le16(timeout);
8993
8994 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8995}
8996
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008997void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
Yu Liu1c6ed312021-04-09 15:04:06 -07008998 u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008999{
Johan Hedbergb644ba32012-01-17 21:48:47 +02009000 char buf[512];
9001 struct mgmt_ev_device_connected *ev = (void *) buf;
9002 u16 eir_len = 0;
Yu Liu1c6ed312021-04-09 15:04:06 -07009003 u32 flags = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02009004
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00009005 bacpy(&ev->addr.bdaddr, &conn->dst);
9006 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02009007
Yu Liu1c6ed312021-04-09 15:04:06 -07009008 if (conn->out)
9009 flags |= MGMT_DEV_FOUND_INITIATED_CONN;
9010
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02009011 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02009012
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009013 /* We must ensure that the EIR Data fields are ordered and
9014 * unique. Keep it simple for now and avoid the problem by not
9015 * adding any BR/EDR data to the LE adv.
9016 */
9017 if (conn->le_adv_data_len > 0) {
9018 memcpy(&ev->eir[eir_len],
9019 conn->le_adv_data, conn->le_adv_data_len);
9020 eir_len = conn->le_adv_data_len;
9021 } else {
9022 if (name_len > 0)
9023 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
9024 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009025
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00009026 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009027 eir_len = eir_append_data(ev->eir, eir_len,
9028 EIR_CLASS_OF_DEV,
9029 conn->dev_class, 3);
9030 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02009031
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009032 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009033
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07009034 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
9035 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02009036}
9037
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009038static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009039{
Johan Hedberg8962ee72011-01-20 12:40:27 +02009040 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009041
Johan Hedbergf5818c22014-12-05 13:36:02 +02009042 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009043
9044 *sk = cmd->sk;
9045 sock_hold(*sk);
9046
Johan Hedberga664b5b2011-02-19 12:06:02 -03009047 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009048}
9049
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009050static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02009051{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009052 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02009053 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02009054
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009055 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
9056
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02009057 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02009058 mgmt_pending_remove(cmd);
9059}
9060
Johan Hedberg84c61d92014-08-01 11:13:30 +03009061bool mgmt_powering_down(struct hci_dev *hdev)
9062{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009063 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03009064 struct mgmt_mode *cp;
9065
Johan Hedberg333ae952015-03-17 13:48:47 +02009066 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03009067 if (!cmd)
9068 return false;
9069
9070 cp = cmd->param;
9071 if (!cp->val)
9072 return true;
9073
9074 return false;
9075}
9076
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009077void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009078 u8 link_type, u8 addr_type, u8 reason,
9079 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02009080{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009081 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009082 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009083
Johan Hedberg84c61d92014-08-01 11:13:30 +03009084 /* The connection is still in hci_conn_hash so test for 1
9085 * instead of 0 to know if this is the last one.
9086 */
9087 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9088 cancel_delayed_work(&hdev->power_off);
9089 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02009090 }
9091
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009092 if (!mgmt_connected)
9093 return;
9094
Andre Guedes57eb7762013-10-30 19:01:41 -03009095 if (link_type != ACL_LINK && link_type != LE_LINK)
9096 return;
9097
Johan Hedberg744cf192011-11-08 20:40:14 +02009098 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02009099
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009100 bacpy(&ev.addr.bdaddr, bdaddr);
9101 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9102 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02009103
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07009104 /* Report disconnects due to suspend */
9105 if (hdev->suspended)
9106 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
9107
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009108 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009109
9110 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01009111 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009112
Johan Hedberg124f6e32012-02-09 13:50:12 +02009113 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009114 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009115}
9116
Marcel Holtmann78929242013-10-06 23:55:47 -07009117void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
9118 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009119{
Andre Guedes3655bba2013-10-30 19:01:40 -03009120 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
9121 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009122 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009123
Jefferson Delfes36a75f12012-09-18 13:36:54 -04009124 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
9125 hdev);
9126
Johan Hedberg333ae952015-03-17 13:48:47 +02009127 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009128 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07009129 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009130
Andre Guedes3655bba2013-10-30 19:01:40 -03009131 cp = cmd->param;
9132
9133 if (bacmp(bdaddr, &cp->addr.bdaddr))
9134 return;
9135
9136 if (cp->addr.type != bdaddr_type)
9137 return;
9138
Johan Hedbergf5818c22014-12-05 13:36:02 +02009139 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009140 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02009141}
Johan Hedberg17d5c042011-01-22 06:09:08 +02009142
Marcel Holtmann445608d2013-10-06 23:55:48 -07009143void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9144 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02009145{
9146 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02009147
Johan Hedberg84c61d92014-08-01 11:13:30 +03009148 /* The connection is still in hci_conn_hash so test for 1
9149 * instead of 0 to know if this is the last one.
9150 */
9151 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9152 cancel_delayed_work(&hdev->power_off);
9153 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02009154 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02009155
Johan Hedberg4c659c32011-11-07 23:13:39 +02009156 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009157 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02009158 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009159
Marcel Holtmann445608d2013-10-06 23:55:48 -07009160 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009161}
Johan Hedberg980e1a52011-01-22 06:10:07 +02009162
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009163void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009164{
9165 struct mgmt_ev_pin_code_request ev;
9166
Johan Hedbergd8457692012-02-17 14:24:57 +02009167 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03009168 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02009169 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009170
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009171 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009172}
9173
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009174void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9175 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009176{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009177 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009178
Johan Hedberg333ae952015-03-17 13:48:47 +02009179 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009180 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009181 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009182
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009183 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009184 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009185}
9186
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009187void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9188 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009189{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009190 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009191
Johan Hedberg333ae952015-03-17 13:48:47 +02009192 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009193 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009194 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009195
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009196 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009197 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009198}
Johan Hedberga5c29682011-02-19 12:05:57 -03009199
Johan Hedberg744cf192011-11-08 20:40:14 +02009200int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02009201 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009202 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03009203{
9204 struct mgmt_ev_user_confirm_request ev;
9205
Marcel Holtmann181d6952020-05-06 09:57:47 +02009206 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03009207
Johan Hedberg272d90d2012-02-09 15:26:12 +02009208 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009209 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07009210 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02009211 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03009212
Johan Hedberg744cf192011-11-08 20:40:14 +02009213 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009214 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03009215}
9216
Johan Hedberg272d90d2012-02-09 15:26:12 +02009217int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009218 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08009219{
9220 struct mgmt_ev_user_passkey_request ev;
9221
Marcel Holtmann181d6952020-05-06 09:57:47 +02009222 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08009223
Johan Hedberg272d90d2012-02-09 15:26:12 +02009224 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009225 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08009226
9227 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009228 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08009229}
9230
Brian Gix0df4c182011-11-16 13:53:13 -08009231static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009232 u8 link_type, u8 addr_type, u8 status,
9233 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03009234{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009235 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03009236
Johan Hedberg333ae952015-03-17 13:48:47 +02009237 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03009238 if (!cmd)
9239 return -ENOENT;
9240
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009241 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009242 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03009243
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009244 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03009245}
9246
Johan Hedberg744cf192011-11-08 20:40:14 +02009247int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009248 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009249{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009250 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009251 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009252}
9253
Johan Hedberg272d90d2012-02-09 15:26:12 +02009254int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009255 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009256{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009257 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009258 status,
9259 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009260}
Johan Hedberg2a611692011-02-19 12:06:00 -03009261
Brian Gix604086b2011-11-23 08:28:33 -08009262int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009263 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009264{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009265 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009266 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009267}
9268
Johan Hedberg272d90d2012-02-09 15:26:12 +02009269int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009270 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009271{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009272 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009273 status,
9274 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009275}
9276
Johan Hedberg92a25252012-09-06 18:39:26 +03009277int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
9278 u8 link_type, u8 addr_type, u32 passkey,
9279 u8 entered)
9280{
9281 struct mgmt_ev_passkey_notify ev;
9282
Marcel Holtmann181d6952020-05-06 09:57:47 +02009283 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03009284
9285 bacpy(&ev.addr.bdaddr, bdaddr);
9286 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9287 ev.passkey = __cpu_to_le32(passkey);
9288 ev.entered = entered;
9289
9290 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
9291}
9292
Johan Hedberge1e930f2014-09-08 17:09:49 -07009293void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03009294{
9295 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009296 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07009297 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03009298
Johan Hedberge1e930f2014-09-08 17:09:49 -07009299 bacpy(&ev.addr.bdaddr, &conn->dst);
9300 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
9301 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03009302
Johan Hedberge1e930f2014-09-08 17:09:49 -07009303 cmd = find_pairing(conn);
9304
9305 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
9306 cmd ? cmd->sk : NULL);
9307
Johan Hedberga511b352014-12-11 21:45:45 +02009308 if (cmd) {
9309 cmd->cmd_complete(cmd, status);
9310 mgmt_pending_remove(cmd);
9311 }
Johan Hedberg2a611692011-02-19 12:06:00 -03009312}
Johan Hedbergb312b1612011-03-16 14:29:37 +02009313
Marcel Holtmann464996a2013-10-15 14:26:24 -07009314void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009315{
9316 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07009317 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009318
9319 if (status) {
9320 u8 mgmt_err = mgmt_status(status);
9321 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009322 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009323 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009324 }
9325
Marcel Holtmann464996a2013-10-15 14:26:24 -07009326 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07009327 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009328 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009329 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02009330
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009331 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009332 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009333
Johan Hedberg47990ea2012-02-22 11:58:37 +02009334 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07009335 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009336
9337 if (match.sk)
9338 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009339}
9340
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009341static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02009342{
9343 struct cmd_lookup *match = data;
9344
Johan Hedberg90e70452012-02-23 23:09:40 +02009345 if (match->sk == NULL) {
9346 match->sk = cmd->sk;
9347 sock_hold(match->sk);
9348 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009349}
9350
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07009351void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
9352 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009353{
Johan Hedberg90e70452012-02-23 23:09:40 +02009354 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009355
Johan Hedberg92da6092013-03-15 17:06:55 -05009356 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
9357 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
9358 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02009359
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009360 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009361 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
9362 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009363 ext_info_changed(hdev, NULL);
9364 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009365
9366 if (match.sk)
9367 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009368}
9369
Marcel Holtmann7667da32013-10-15 14:26:27 -07009370void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02009371{
Johan Hedbergb312b1612011-03-16 14:29:37 +02009372 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009373 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009374
Johan Hedberg13928972013-03-15 17:07:00 -05009375 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07009376 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009377
9378 memset(&ev, 0, sizeof(ev));
9379 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009380 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009381
Johan Hedberg333ae952015-03-17 13:48:47 +02009382 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05009383 if (!cmd) {
9384 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02009385
Johan Hedberg13928972013-03-15 17:07:00 -05009386 /* If this is a HCI command related to powering on the
9387 * HCI dev don't send any mgmt signals.
9388 */
Johan Hedberg333ae952015-03-17 13:48:47 +02009389 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07009390 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009391 }
9392
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009393 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
9394 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009395 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009396}
Szymon Jancc35938b2011-03-22 13:12:21 +01009397
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009398static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
9399{
9400 int i;
9401
9402 for (i = 0; i < uuid_count; i++) {
9403 if (!memcmp(uuid, uuids[i], 16))
9404 return true;
9405 }
9406
9407 return false;
9408}
9409
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009410static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
9411{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009412 u16 parsed = 0;
9413
9414 while (parsed < eir_len) {
9415 u8 field_len = eir[0];
9416 u8 uuid[16];
9417 int i;
9418
9419 if (field_len == 0)
9420 break;
9421
9422 if (eir_len - parsed < field_len + 1)
9423 break;
9424
9425 switch (eir[1]) {
9426 case EIR_UUID16_ALL:
9427 case EIR_UUID16_SOME:
9428 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009429 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009430 uuid[13] = eir[i + 3];
9431 uuid[12] = eir[i + 2];
9432 if (has_uuid(uuid, uuid_count, uuids))
9433 return true;
9434 }
9435 break;
9436 case EIR_UUID32_ALL:
9437 case EIR_UUID32_SOME:
9438 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009439 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009440 uuid[15] = eir[i + 5];
9441 uuid[14] = eir[i + 4];
9442 uuid[13] = eir[i + 3];
9443 uuid[12] = eir[i + 2];
9444 if (has_uuid(uuid, uuid_count, uuids))
9445 return true;
9446 }
9447 break;
9448 case EIR_UUID128_ALL:
9449 case EIR_UUID128_SOME:
9450 for (i = 0; i + 17 <= field_len; i += 16) {
9451 memcpy(uuid, eir + i + 2, 16);
9452 if (has_uuid(uuid, uuid_count, uuids))
9453 return true;
9454 }
9455 break;
9456 }
9457
9458 parsed += field_len + 1;
9459 eir += field_len + 1;
9460 }
9461
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009462 return false;
9463}
9464
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009465static void restart_le_scan(struct hci_dev *hdev)
9466{
9467 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009468 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009469 return;
9470
9471 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
9472 hdev->discovery.scan_start +
9473 hdev->discovery.scan_duration))
9474 return;
9475
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02009476 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009477 DISCOV_LE_RESTART_DELAY);
9478}
9479
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009480static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
9481 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
9482{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009483 /* If a RSSI threshold has been specified, and
9484 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
9485 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
9486 * is set, let it through for further processing, as we might need to
9487 * restart the scan.
9488 *
9489 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
9490 * the results are also dropped.
9491 */
9492 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9493 (rssi == HCI_RSSI_INVALID ||
9494 (rssi < hdev->discovery.rssi &&
9495 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
9496 return false;
9497
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009498 if (hdev->discovery.uuid_count != 0) {
9499 /* If a list of UUIDs is provided in filter, results with no
9500 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009501 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009502 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
9503 hdev->discovery.uuids) &&
9504 !eir_has_uuids(scan_rsp, scan_rsp_len,
9505 hdev->discovery.uuid_count,
9506 hdev->discovery.uuids))
9507 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009508 }
9509
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009510 /* If duplicate filtering does not report RSSI changes, then restart
9511 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009512 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009513 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
9514 restart_le_scan(hdev);
9515
9516 /* Validate RSSI value against the RSSI threshold once more. */
9517 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9518 rssi < hdev->discovery.rssi)
9519 return false;
9520 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009521
9522 return true;
9523}
9524
Marcel Holtmann901801b2013-10-06 23:55:51 -07009525void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02009526 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
9527 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03009528{
Johan Hedberge319d2e2012-01-15 19:51:59 +02009529 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009530 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02009531 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03009532
Johan Hedberg75ce2082014-07-02 22:42:01 +03009533 /* Don't send events for a non-kernel initiated discovery. With
9534 * LE one exception is if we have pend_le_reports > 0 in which
9535 * case we're doing passive scanning and want these events.
9536 */
9537 if (!hci_discovery_active(hdev)) {
9538 if (link_type == ACL_LINK)
9539 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009540 if (link_type == LE_LINK &&
9541 list_empty(&hdev->pend_le_reports) &&
9542 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03009543 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009544 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03009545 }
Andre Guedes12602d02013-04-30 15:29:40 -03009546
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08009547 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009548 /* We are using service discovery */
9549 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
9550 scan_rsp_len))
9551 return;
9552 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01009553
Johan Hedberg78b781c2016-01-05 13:19:32 +02009554 if (hdev->discovery.limited) {
9555 /* Check for limited discoverable bit */
9556 if (dev_class) {
9557 if (!(dev_class[1] & 0x20))
9558 return;
9559 } else {
9560 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
9561 if (!flags || !(flags[0] & LE_AD_LIMITED))
9562 return;
9563 }
9564 }
9565
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009566 /* Make sure that the buffer is big enough. The 5 extra bytes
9567 * are for the potential CoD field.
9568 */
9569 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07009570 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03009571
Johan Hedberg1dc06092012-01-15 21:01:23 +02009572 memset(buf, 0, sizeof(buf));
9573
Marcel Holtmannda25cf62014-12-05 13:03:35 +01009574 /* In case of device discovery with BR/EDR devices (pre 1.2), the
9575 * RSSI value was reported as 0 when not available. This behavior
9576 * is kept when using device discovery. This is required for full
9577 * backwards compatibility with the API.
9578 *
9579 * However when using service discovery, the value 127 will be
9580 * returned when the RSSI is not available.
9581 */
Szymon Janc91200e92015-01-22 16:57:05 +01009582 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
9583 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01009584 rssi = 0;
9585
Johan Hedberg841c5642014-07-07 12:45:54 +03009586 bacpy(&ev->addr.bdaddr, bdaddr);
9587 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02009588 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02009589 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03009590
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009591 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009592 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02009593 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03009594
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02009595 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
9596 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02009597 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009598 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02009599
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009600 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009601 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009602 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009603
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009604 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
9605 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03009606
Marcel Holtmann901801b2013-10-06 23:55:51 -07009607 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03009608}
Johan Hedberga88a9652011-03-30 13:18:12 +03009609
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009610void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9611 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03009612{
Johan Hedbergb644ba32012-01-17 21:48:47 +02009613 struct mgmt_ev_device_found *ev;
9614 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
9615 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03009616
Johan Hedbergb644ba32012-01-17 21:48:47 +02009617 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03009618
Johan Hedbergb644ba32012-01-17 21:48:47 +02009619 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03009620
Johan Hedbergb644ba32012-01-17 21:48:47 +02009621 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009622 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009623 ev->rssi = rssi;
9624
9625 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009626 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009627
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009628 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009629
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009630 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03009631}
Johan Hedberg314b2382011-04-27 10:29:57 -04009632
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009633void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04009634{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009635 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02009636
Marcel Holtmann181d6952020-05-06 09:57:47 +02009637 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03009638
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009639 memset(&ev, 0, sizeof(ev));
9640 ev.type = hdev->discovery.type;
9641 ev.discovering = discovering;
9642
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009643 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04009644}
Antti Julku5e762442011-08-25 16:48:02 +03009645
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07009646void mgmt_suspending(struct hci_dev *hdev, u8 state)
9647{
9648 struct mgmt_ev_controller_suspend ev;
9649
9650 ev.suspend_state = state;
9651 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
9652}
9653
9654void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
9655 u8 addr_type)
9656{
9657 struct mgmt_ev_controller_resume ev;
9658
9659 ev.wake_reason = reason;
9660 if (bdaddr) {
9661 bacpy(&ev.addr.bdaddr, bdaddr);
9662 ev.addr.type = addr_type;
9663 } else {
9664 memset(&ev.addr, 0, sizeof(ev.addr));
9665 }
9666
9667 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
9668}
9669
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009670static struct hci_mgmt_chan chan = {
9671 .channel = HCI_CHANNEL_CONTROL,
9672 .handler_count = ARRAY_SIZE(mgmt_handlers),
9673 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02009674 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009675};
9676
9677int mgmt_init(void)
9678{
9679 return hci_mgmt_chan_register(&chan);
9680}
9681
9682void mgmt_exit(void)
9683{
9684 hci_mgmt_chan_unregister(&chan);
9685}