blob: 37087cf7dc5aff20fa0ce69242f28cfee8203d8f [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
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -0800338static int mgmt_event_skb(struct sk_buff *skb, struct sock *skip_sk)
339{
340 return mgmt_send_event_skb(HCI_CHANNEL_CONTROL, skb, HCI_SOCK_TRUSTED,
341 skip_sk);
342}
343
Johan Hedberg85813a72015-10-21 18:02:59 +0300344static u8 le_addr_type(u8 mgmt_addr_type)
345{
346 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
347 return ADDR_LE_DEV_PUBLIC;
348 else
349 return ADDR_LE_DEV_RANDOM;
350}
351
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200352void mgmt_fill_version_info(void *ver)
353{
354 struct mgmt_rp_read_version *rp = ver;
355
356 rp->version = MGMT_VERSION;
357 rp->revision = cpu_to_le16(MGMT_REVISION);
358}
359
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300360static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
361 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200362{
363 struct mgmt_rp_read_version rp;
364
Marcel Holtmann181d6952020-05-06 09:57:47 +0200365 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200366
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200367 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200368
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200369 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
370 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200371}
372
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300373static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
374 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200375{
376 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700377 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200378 size_t rp_size;
379 int i, err;
380
Marcel Holtmann181d6952020-05-06 09:57:47 +0200381 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200382
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700383 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
384 num_commands = ARRAY_SIZE(mgmt_commands);
385 num_events = ARRAY_SIZE(mgmt_events);
386 } else {
387 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
388 num_events = ARRAY_SIZE(mgmt_untrusted_events);
389 }
390
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200391 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
392
393 rp = kmalloc(rp_size, GFP_KERNEL);
394 if (!rp)
395 return -ENOMEM;
396
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700397 rp->num_commands = cpu_to_le16(num_commands);
398 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200399
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700400 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
401 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200402
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700403 for (i = 0; i < num_commands; i++, opcode++)
404 put_unaligned_le16(mgmt_commands[i], opcode);
405
406 for (i = 0; i < num_events; i++, opcode++)
407 put_unaligned_le16(mgmt_events[i], opcode);
408 } else {
409 __le16 *opcode = rp->opcodes;
410
411 for (i = 0; i < num_commands; i++, opcode++)
412 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
413
414 for (i = 0; i < num_events; i++, opcode++)
415 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
416 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200417
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200418 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
419 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200420 kfree(rp);
421
422 return err;
423}
424
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300425static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
426 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200427{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200429 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200430 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200431 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300432 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200433
Marcel Holtmann181d6952020-05-06 09:57:47 +0200434 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200435
436 read_lock(&hci_dev_list_lock);
437
438 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300439 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200440 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700441 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700442 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200443 }
444
Johan Hedberga38528f2011-01-22 06:46:43 +0200445 rp_len = sizeof(*rp) + (2 * count);
446 rp = kmalloc(rp_len, GFP_ATOMIC);
447 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100448 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200449 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100450 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200451
Johan Hedberg476e44c2012-10-19 20:10:46 +0300452 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200453 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700454 if (hci_dev_test_flag(d, HCI_SETUP) ||
455 hci_dev_test_flag(d, HCI_CONFIG) ||
456 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200457 continue;
458
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200459 /* Devices marked as raw-only are neither configured
460 * nor unconfigured controllers.
461 */
462 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700463 continue;
464
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200465 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700466 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700467 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200468 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700469 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200470 }
471
Johan Hedberg476e44c2012-10-19 20:10:46 +0300472 rp->num_controllers = cpu_to_le16(count);
473 rp_len = sizeof(*rp) + (2 * count);
474
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200475 read_unlock(&hci_dev_list_lock);
476
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200477 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
478 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200479
Johan Hedberga38528f2011-01-22 06:46:43 +0200480 kfree(rp);
481
482 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200483}
484
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200485static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
486 void *data, u16 data_len)
487{
488 struct mgmt_rp_read_unconf_index_list *rp;
489 struct hci_dev *d;
490 size_t rp_len;
491 u16 count;
492 int err;
493
Marcel Holtmann181d6952020-05-06 09:57:47 +0200494 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200495
496 read_lock(&hci_dev_list_lock);
497
498 count = 0;
499 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200500 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700501 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200502 count++;
503 }
504
505 rp_len = sizeof(*rp) + (2 * count);
506 rp = kmalloc(rp_len, GFP_ATOMIC);
507 if (!rp) {
508 read_unlock(&hci_dev_list_lock);
509 return -ENOMEM;
510 }
511
512 count = 0;
513 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700514 if (hci_dev_test_flag(d, HCI_SETUP) ||
515 hci_dev_test_flag(d, HCI_CONFIG) ||
516 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200517 continue;
518
519 /* Devices marked as raw-only are neither configured
520 * nor unconfigured controllers.
521 */
522 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
523 continue;
524
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200525 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700526 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200527 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200528 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200529 }
530 }
531
532 rp->num_controllers = cpu_to_le16(count);
533 rp_len = sizeof(*rp) + (2 * count);
534
535 read_unlock(&hci_dev_list_lock);
536
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200537 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
538 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200539
540 kfree(rp);
541
542 return err;
543}
544
Marcel Holtmann96f14742015-03-14 19:27:57 -0700545static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
546 void *data, u16 data_len)
547{
548 struct mgmt_rp_read_ext_index_list *rp;
549 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700550 u16 count;
551 int err;
552
Marcel Holtmann181d6952020-05-06 09:57:47 +0200553 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700554
555 read_lock(&hci_dev_list_lock);
556
557 count = 0;
558 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200559 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700560 count++;
561 }
562
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600563 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700564 if (!rp) {
565 read_unlock(&hci_dev_list_lock);
566 return -ENOMEM;
567 }
568
569 count = 0;
570 list_for_each_entry(d, &hci_dev_list, list) {
571 if (hci_dev_test_flag(d, HCI_SETUP) ||
572 hci_dev_test_flag(d, HCI_CONFIG) ||
573 hci_dev_test_flag(d, HCI_USER_CHANNEL))
574 continue;
575
576 /* Devices marked as raw-only are neither configured
577 * nor unconfigured controllers.
578 */
579 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
580 continue;
581
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200582 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700583 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
584 rp->entry[count].type = 0x01;
585 else
586 rp->entry[count].type = 0x00;
587 } else if (d->dev_type == HCI_AMP) {
588 rp->entry[count].type = 0x02;
589 } else {
590 continue;
591 }
592
593 rp->entry[count].bus = d->bus;
594 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200595 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700596 }
597
598 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700599
600 read_unlock(&hci_dev_list_lock);
601
602 /* If this command is called at least once, then all the
603 * default index and unconfigured index events are disabled
604 * and from now on only extended index events are used.
605 */
606 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
607 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
608 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
609
610 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600611 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
612 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700613
614 kfree(rp);
615
616 return err;
617}
618
Marcel Holtmanndbece372014-07-04 18:11:55 +0200619static bool is_configured(struct hci_dev *hdev)
620{
621 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700622 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200623 return false;
624
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800625 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
626 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200627 !bacmp(&hdev->public_addr, BDADDR_ANY))
628 return false;
629
630 return true;
631}
632
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200633static __le32 get_missing_options(struct hci_dev *hdev)
634{
635 u32 options = 0;
636
Marcel Holtmanndbece372014-07-04 18:11:55 +0200637 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700638 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200639 options |= MGMT_OPTION_EXTERNAL_CONFIG;
640
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800641 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
642 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200643 !bacmp(&hdev->public_addr, BDADDR_ANY))
644 options |= MGMT_OPTION_PUBLIC_ADDRESS;
645
646 return cpu_to_le32(options);
647}
648
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200649static int new_options(struct hci_dev *hdev, struct sock *skip)
650{
651 __le32 options = get_missing_options(hdev);
652
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200653 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
654 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200655}
656
Marcel Holtmanndbece372014-07-04 18:11:55 +0200657static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
658{
659 __le32 options = get_missing_options(hdev);
660
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200661 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
662 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200663}
664
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200665static int read_config_info(struct sock *sk, struct hci_dev *hdev,
666 void *data, u16 data_len)
667{
668 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200669 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200670
Marcel Holtmann181d6952020-05-06 09:57:47 +0200671 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200672
673 hci_dev_lock(hdev);
674
675 memset(&rp, 0, sizeof(rp));
676 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200677
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200678 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
679 options |= MGMT_OPTION_EXTERNAL_CONFIG;
680
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200681 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200682 options |= MGMT_OPTION_PUBLIC_ADDRESS;
683
684 rp.supported_options = cpu_to_le32(options);
685 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200686
687 hci_dev_unlock(hdev);
688
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200689 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
690 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200691}
692
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530693static u32 get_supported_phys(struct hci_dev *hdev)
694{
695 u32 supported_phys = 0;
696
697 if (lmp_bredr_capable(hdev)) {
698 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
699
700 if (hdev->features[0][0] & LMP_3SLOT)
701 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
702
703 if (hdev->features[0][0] & LMP_5SLOT)
704 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
705
706 if (lmp_edr_2m_capable(hdev)) {
707 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
708
709 if (lmp_edr_3slot_capable(hdev))
710 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
711
712 if (lmp_edr_5slot_capable(hdev))
713 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
714
715 if (lmp_edr_3m_capable(hdev)) {
716 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
717
718 if (lmp_edr_3slot_capable(hdev))
719 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
720
721 if (lmp_edr_5slot_capable(hdev))
722 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
723 }
724 }
725 }
726
727 if (lmp_le_capable(hdev)) {
728 supported_phys |= MGMT_PHY_LE_1M_TX;
729 supported_phys |= MGMT_PHY_LE_1M_RX;
730
731 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
732 supported_phys |= MGMT_PHY_LE_2M_TX;
733 supported_phys |= MGMT_PHY_LE_2M_RX;
734 }
735
736 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
737 supported_phys |= MGMT_PHY_LE_CODED_TX;
738 supported_phys |= MGMT_PHY_LE_CODED_RX;
739 }
740 }
741
742 return supported_phys;
743}
744
745static u32 get_selected_phys(struct hci_dev *hdev)
746{
747 u32 selected_phys = 0;
748
749 if (lmp_bredr_capable(hdev)) {
750 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
751
752 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
753 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
754
755 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
756 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
757
758 if (lmp_edr_2m_capable(hdev)) {
759 if (!(hdev->pkt_type & HCI_2DH1))
760 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
761
762 if (lmp_edr_3slot_capable(hdev) &&
763 !(hdev->pkt_type & HCI_2DH3))
764 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
765
766 if (lmp_edr_5slot_capable(hdev) &&
767 !(hdev->pkt_type & HCI_2DH5))
768 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
769
770 if (lmp_edr_3m_capable(hdev)) {
771 if (!(hdev->pkt_type & HCI_3DH1))
772 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
773
774 if (lmp_edr_3slot_capable(hdev) &&
775 !(hdev->pkt_type & HCI_3DH3))
776 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
777
778 if (lmp_edr_5slot_capable(hdev) &&
779 !(hdev->pkt_type & HCI_3DH5))
780 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
781 }
782 }
783 }
784
785 if (lmp_le_capable(hdev)) {
786 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
787 selected_phys |= MGMT_PHY_LE_1M_TX;
788
789 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
790 selected_phys |= MGMT_PHY_LE_1M_RX;
791
792 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
793 selected_phys |= MGMT_PHY_LE_2M_TX;
794
795 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
796 selected_phys |= MGMT_PHY_LE_2M_RX;
797
798 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
799 selected_phys |= MGMT_PHY_LE_CODED_TX;
800
801 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
802 selected_phys |= MGMT_PHY_LE_CODED_RX;
803 }
804
805 return selected_phys;
806}
807
808static u32 get_configurable_phys(struct hci_dev *hdev)
809{
810 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
811 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
812}
813
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200814static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200815{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200816 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200817
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200818 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300819 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800820 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300821 settings |= MGMT_SETTING_CONNECTABLE;
822 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200823
Andre Guedesed3fa312012-07-24 15:03:46 -0300824 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500825 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
826 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827 settings |= MGMT_SETTING_BREDR;
828 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700829
830 if (lmp_ssp_capable(hdev)) {
831 settings |= MGMT_SETTING_SSP;
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -0700832 if (IS_ENABLED(CONFIG_BT_HS))
833 settings |= MGMT_SETTING_HS;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700834 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800835
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800836 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800837 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000838
Alain Michaud00bce3f2020-03-05 16:14:59 +0000839 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000840 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000841 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700842 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100843
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300844 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200845 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300846 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200847 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800848 settings |= MGMT_SETTING_STATIC_ADDRESS;
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -0700849 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300850 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200851
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200852 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
853 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200854 settings |= MGMT_SETTING_CONFIGURATION;
855
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530856 settings |= MGMT_SETTING_PHY_CONFIGURATION;
857
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200858 return settings;
859}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200860
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200861static u32 get_current_settings(struct hci_dev *hdev)
862{
863 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200864
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200865 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100866 settings |= MGMT_SETTING_POWERED;
867
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700868 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200869 settings |= MGMT_SETTING_CONNECTABLE;
870
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700871 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500872 settings |= MGMT_SETTING_FAST_CONNECTABLE;
873
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700874 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200875 settings |= MGMT_SETTING_DISCOVERABLE;
876
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700877 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300878 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200879
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700880 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200881 settings |= MGMT_SETTING_BREDR;
882
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700883 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200884 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200885
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700886 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200887 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200888
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700889 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200890 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200891
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700892 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200893 settings |= MGMT_SETTING_HS;
894
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700895 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300896 settings |= MGMT_SETTING_ADVERTISING;
897
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700898 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800899 settings |= MGMT_SETTING_SECURE_CONN;
900
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700901 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800902 settings |= MGMT_SETTING_DEBUG_KEYS;
903
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700904 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200905 settings |= MGMT_SETTING_PRIVACY;
906
Marcel Holtmann93690c22015-03-06 10:11:21 -0800907 /* The current setting for static address has two purposes. The
908 * first is to indicate if the static address will be used and
909 * the second is to indicate if it is actually set.
910 *
911 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700912 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800913 * address is actually used decides if the flag is set or not.
914 *
915 * For single mode LE only controllers and dual-mode controllers
916 * with BR/EDR disabled, the existence of the static address will
917 * be evaluated.
918 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700919 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700920 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800921 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
922 if (bacmp(&hdev->static_addr, BDADDR_ANY))
923 settings |= MGMT_SETTING_STATIC_ADDRESS;
924 }
925
Alain Michaud00bce3f2020-03-05 16:14:59 +0000926 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
927 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
928
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200929 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200930}
931
Johan Hedberg333ae952015-03-17 13:48:47 +0200932static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
933{
934 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
935}
936
Johan Hedbergf2252572015-11-18 12:49:20 +0200937u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300938{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200939 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300940
941 /* If there's a pending mgmt command the flags will not yet have
942 * their final values, so check for this first.
943 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200944 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300945 if (cmd) {
946 struct mgmt_mode *cp = cmd->param;
947 if (cp->val == 0x01)
948 return LE_AD_GENERAL;
949 else if (cp->val == 0x02)
950 return LE_AD_LIMITED;
951 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700952 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300953 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700954 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300955 return LE_AD_GENERAL;
956 }
957
958 return 0;
959}
960
Johan Hedbergf2252572015-11-18 12:49:20 +0200961bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700962{
963 struct mgmt_pending_cmd *cmd;
964
965 /* If there's a pending mgmt command the flag will not yet have
966 * it's final value, so check for this first.
967 */
968 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
969 if (cmd) {
970 struct mgmt_mode *cp = cmd->param;
971
972 return cp->val;
973 }
974
975 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
976}
977
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700978static int service_cache_sync(struct hci_dev *hdev, void *data)
979{
980 hci_update_eir_sync(hdev);
981 hci_update_class_sync(hdev);
982
983 return 0;
984}
985
Johan Hedberg7d785252011-12-15 00:47:39 +0200986static void service_cache_off(struct work_struct *work)
987{
988 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300989 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200990
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700991 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200992 return;
993
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -0700994 hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200995}
996
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -0700997static int rpa_expired_sync(struct hci_dev *hdev, void *data)
998{
999 /* The generation of a new RPA and programming it into the
1000 * controller happens in the hci_req_enable_advertising()
1001 * function.
1002 */
1003 if (ext_adv_capable(hdev))
1004 return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
1005 else
1006 return hci_enable_advertising_sync(hdev);
1007}
1008
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001009static void rpa_expired(struct work_struct *work)
1010{
1011 struct hci_dev *hdev = container_of(work, struct hci_dev,
1012 rpa_expired.work);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001013
Marcel Holtmann181d6952020-05-06 09:57:47 +02001014 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001015
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001016 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001017
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001018 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001019 return;
1020
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07001021 hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001022}
1023
Johan Hedberg6a919082012-02-28 06:17:26 +02001024static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001025{
Marcel Holtmann238be782015-03-13 02:11:06 -07001026 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001027 return;
1028
Johan Hedberg4f87da82012-03-02 19:55:56 +02001029 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001030 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001031
Johan Hedberg4f87da82012-03-02 19:55:56 +02001032 /* Non-mgmt controlled devices get this bit set
1033 * implicitly so that pairing works for them, however
1034 * for mgmt we require user-space to explicitly enable
1035 * it
1036 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001037 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001038}
1039
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001040static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001041 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001042{
1043 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001044
Marcel Holtmann181d6952020-05-06 09:57:47 +02001045 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001046
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001047 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001048
Johan Hedberg03811012010-12-08 00:21:06 +02001049 memset(&rp, 0, sizeof(rp));
1050
Johan Hedberg03811012010-12-08 00:21:06 +02001051 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001052
1053 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001054 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001055
1056 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1057 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1058
1059 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001060
1061 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001062 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001063
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001064 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001065
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001066 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1067 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001068}
1069
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001070static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1071{
1072 u16 eir_len = 0;
1073 size_t name_len;
1074
1075 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1076 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1077 hdev->dev_class, 3);
1078
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001079 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1080 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1081 hdev->appearance);
1082
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001083 name_len = strlen(hdev->dev_name);
1084 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1085 hdev->dev_name, name_len);
1086
1087 name_len = strlen(hdev->short_name);
1088 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1089 hdev->short_name, name_len);
1090
1091 return eir_len;
1092}
1093
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001094static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1095 void *data, u16 data_len)
1096{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001097 char buf[512];
1098 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001099 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001100
Marcel Holtmann181d6952020-05-06 09:57:47 +02001101 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001102
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001103 memset(&buf, 0, sizeof(buf));
1104
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001105 hci_dev_lock(hdev);
1106
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001107 bacpy(&rp->bdaddr, &hdev->bdaddr);
1108
1109 rp->version = hdev->hci_ver;
1110 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1111
1112 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1113 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001114
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001115
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001116 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001117 rp->eir_len = cpu_to_le16(eir_len);
1118
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001119 hci_dev_unlock(hdev);
1120
1121 /* If this command is called at least once, then the events
1122 * for class of device and local name changes are disabled
1123 * and only the new extended controller information event
1124 * is used.
1125 */
1126 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1127 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1128 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1129
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001130 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1131 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001132}
1133
1134static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1135{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001136 char buf[512];
1137 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1138 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001139
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001140 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001141
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001142 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1143 ev->eir_len = cpu_to_le16(eir_len);
1144
1145 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1146 sizeof(*ev) + eir_len,
1147 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001148}
1149
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001150static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001151{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001152 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001153
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001154 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1155 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001156}
1157
Johan Hedbergf2252572015-11-18 12:49:20 +02001158void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001159{
1160 struct mgmt_ev_advertising_added ev;
1161
1162 ev.instance = instance;
1163
1164 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1165}
1166
Johan Hedbergf2252572015-11-18 12:49:20 +02001167void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1168 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001169{
1170 struct mgmt_ev_advertising_removed ev;
1171
1172 ev.instance = instance;
1173
1174 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1175}
1176
Florian Grandel7816b822015-06-18 03:16:45 +02001177static void cancel_adv_timeout(struct hci_dev *hdev)
1178{
1179 if (hdev->adv_instance_timeout) {
1180 hdev->adv_instance_timeout = 0;
1181 cancel_delayed_work(&hdev->adv_instance_expire);
1182 }
1183}
1184
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001185/* This function requires the caller holds hdev->lock */
1186static void restart_le_actions(struct hci_dev *hdev)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001187{
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001188 struct hci_conn_params *p;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001189
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001190 list_for_each_entry(p, &hdev->le_conn_params, list) {
1191 /* Needed for AUTO_OFF case where might not "really"
1192 * have been powered off.
1193 */
1194 list_del_init(&p->action);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001195
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001196 switch (p->auto_connect) {
1197 case HCI_AUTO_CONN_DIRECT:
1198 case HCI_AUTO_CONN_ALWAYS:
1199 list_add(&p->action, &hdev->pend_le_conns);
1200 break;
1201 case HCI_AUTO_CONN_REPORT:
1202 list_add(&p->action, &hdev->pend_le_reports);
1203 break;
1204 default:
1205 break;
1206 }
1207 }
1208}
1209
1210static int new_settings(struct hci_dev *hdev, struct sock *skip)
1211{
1212 __le32 ev = cpu_to_le32(get_current_settings(hdev));
1213
1214 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1215 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
1216}
1217
1218static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
1219{
1220 struct mgmt_pending_cmd *cmd = data;
1221 struct mgmt_mode *cp = cmd->param;
1222
1223 bt_dev_dbg(hdev, "err %d", err);
1224
1225 if (!err) {
1226 if (cp->val) {
1227 hci_dev_lock(hdev);
1228 restart_le_actions(hdev);
1229 hci_update_passive_scan(hdev);
1230 hci_dev_unlock(hdev);
1231 }
1232
1233 send_settings_rsp(cmd->sk, cmd->opcode, hdev);
1234
1235 /* Only call new_setting for power on as power off is deferred
1236 * to hdev->power_off work which does call hci_dev_do_close.
1237 */
1238 if (cp->val)
1239 new_settings(hdev, cmd->sk);
1240 } else {
1241 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED,
1242 mgmt_status(err));
Johan Hedberg8b064a32014-02-24 14:52:22 +02001243 }
1244
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001245 mgmt_pending_free(cmd);
1246}
Arman Uguray912098a2015-03-23 15:57:15 -07001247
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001248static int set_powered_sync(struct hci_dev *hdev, void *data)
1249{
1250 struct mgmt_pending_cmd *cmd = data;
1251 struct mgmt_mode *cp = cmd->param;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001252
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001253 BT_DBG("%s", hdev->name);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001254
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001255 return hci_set_powered_sync(hdev, cp->val);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001256}
1257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001258static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001259 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001260{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001261 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001262 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001263 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001264
Marcel Holtmann181d6952020-05-06 09:57:47 +02001265 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001266
Johan Hedberga7e80f22013-01-09 16:05:19 +02001267 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001268 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1269 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001272
Johan Hedberg333ae952015-03-17 13:48:47 +02001273 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001274 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1275 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001276 goto failed;
1277 }
1278
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001279 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001280 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001281 goto failed;
1282 }
1283
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001284 cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001285 if (!cmd) {
1286 err = -ENOMEM;
1287 goto failed;
1288 }
1289
Luiz Augusto von Dentzcf75ad82021-10-27 16:58:44 -07001290 err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
1291 mgmt_set_powered_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001292
1293failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001294 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001295 return err;
1296}
1297
Johan Hedberg91a668b2014-07-09 13:28:26 +03001298int mgmt_new_settings(struct hci_dev *hdev)
1299{
1300 return new_settings(hdev, NULL);
1301}
1302
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001303struct cmd_lookup {
1304 struct sock *sk;
1305 struct hci_dev *hdev;
1306 u8 mgmt_status;
1307};
1308
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001309static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001310{
1311 struct cmd_lookup *match = data;
1312
1313 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1314
1315 list_del(&cmd->list);
1316
1317 if (match->sk == NULL) {
1318 match->sk = cmd->sk;
1319 sock_hold(match->sk);
1320 }
1321
1322 mgmt_pending_free(cmd);
1323}
1324
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001325static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001326{
1327 u8 *status = data;
1328
Johan Hedberga69e8372015-03-06 21:08:53 +02001329 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001330 mgmt_pending_remove(cmd);
1331}
1332
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001333static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001334{
1335 if (cmd->cmd_complete) {
1336 u8 *status = data;
1337
1338 cmd->cmd_complete(cmd, *status);
1339 mgmt_pending_remove(cmd);
1340
1341 return;
1342 }
1343
1344 cmd_status_rsp(cmd, data);
1345}
1346
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001348{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001349 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1350 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001351}
1352
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001353static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001354{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001355 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1356 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001357}
1358
Johan Hedberge6fe7982013-10-02 15:45:22 +03001359static u8 mgmt_bredr_support(struct hci_dev *hdev)
1360{
1361 if (!lmp_bredr_capable(hdev))
1362 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001363 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001364 return MGMT_STATUS_REJECTED;
1365 else
1366 return MGMT_STATUS_SUCCESS;
1367}
1368
1369static u8 mgmt_le_support(struct hci_dev *hdev)
1370{
1371 if (!lmp_le_capable(hdev))
1372 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001373 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001374 return MGMT_STATUS_REJECTED;
1375 else
1376 return MGMT_STATUS_SUCCESS;
1377}
1378
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001379static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
1380 int err)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001381{
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001382 struct mgmt_pending_cmd *cmd = data;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001383
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001384 bt_dev_dbg(hdev, "err %d", err);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001385
1386 hci_dev_lock(hdev);
1387
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001388 if (err) {
1389 u8 mgmt_err = mgmt_status(err);
Johan Hedberga69e8372015-03-06 21:08:53 +02001390 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001391 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001392 goto done;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001393 }
1394
Johan Hedbergaed1a882015-11-22 17:24:44 +03001395 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1396 hdev->discov_timeout > 0) {
1397 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1398 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001399 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001400
1401 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001402 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001403
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001404done:
1405 mgmt_pending_free(cmd);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001406 hci_dev_unlock(hdev);
1407}
1408
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001409static int set_discoverable_sync(struct hci_dev *hdev, void *data)
1410{
1411 BT_DBG("%s", hdev->name);
1412
1413 return hci_update_discoverable_sync(hdev);
1414}
1415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001416static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001417 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001418{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001419 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001420 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001421 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422 int err;
1423
Marcel Holtmann181d6952020-05-06 09:57:47 +02001424 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001425
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001426 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1427 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001428 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1429 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001430
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001431 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1433 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001434
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001435 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001436
1437 /* Disabling discoverable requires that no timeout is set,
1438 * and enabling limited discoverable requires a timeout.
1439 */
1440 if ((cp->val == 0x00 && timeout > 0) ||
1441 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001442 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1443 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001445 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001446
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001447 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001448 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1449 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001450 goto failed;
1451 }
1452
Johan Hedberg333ae952015-03-17 13:48:47 +02001453 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1454 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001455 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1456 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001457 goto failed;
1458 }
1459
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001460 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001461 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1462 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001463 goto failed;
1464 }
1465
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001466 if (hdev->advertising_paused) {
1467 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1468 MGMT_STATUS_BUSY);
1469 goto failed;
1470 }
1471
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001472 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001473 bool changed = false;
1474
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001475 /* Setting limited discoverable when powered off is
1476 * not a valid operation since it requires a timeout
1477 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1478 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001479 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001480 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001481 changed = true;
1482 }
1483
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001484 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001485 if (err < 0)
1486 goto failed;
1487
1488 if (changed)
1489 err = new_settings(hdev, sk);
1490
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001491 goto failed;
1492 }
1493
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001494 /* If the current mode is the same, then just update the timeout
1495 * value with the new value. And if only the timeout gets updated,
1496 * then no need for any HCI transactions.
1497 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001498 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1499 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1500 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001501 cancel_delayed_work(&hdev->discov_off);
1502 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001503
Marcel Holtmann36261542013-10-15 08:28:51 -07001504 if (cp->val && hdev->discov_timeout > 0) {
1505 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001506 queue_delayed_work(hdev->req_workqueue,
1507 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001508 }
1509
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001510 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001511 goto failed;
1512 }
1513
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001514 cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001515 if (!cmd) {
1516 err = -ENOMEM;
1517 goto failed;
1518 }
1519
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001520 /* Cancel any potential discoverable timeout that might be
1521 * still active and store new timeout value. The arming of
1522 * the timeout happens in the complete handler.
1523 */
1524 cancel_delayed_work(&hdev->discov_off);
1525 hdev->discov_timeout = timeout;
1526
Johan Hedbergaed1a882015-11-22 17:24:44 +03001527 if (cp->val)
1528 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1529 else
1530 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1531
Johan Hedbergb456f872013-10-19 23:38:22 +03001532 /* Limited discoverable mode */
1533 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001534 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001535 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001536 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001537
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001538 err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd,
1539 mgmt_set_discoverable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001540
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001541failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001542 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001543 return err;
1544}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001545
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001546static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
1547 int err)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001548{
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001549 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001550
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001551 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001552
1553 hci_dev_lock(hdev);
1554
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001555 if (err) {
1556 u8 mgmt_err = mgmt_status(err);
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001558 goto done;
Johan Hedberg37438c12013-10-14 16:20:05 +03001559 }
1560
Johan Hedberg2b76f452013-03-15 17:07:04 -05001561 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001562 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001563
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001564done:
1565 mgmt_pending_free(cmd);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001566 hci_dev_unlock(hdev);
1567}
1568
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001569static int set_connectable_update_settings(struct hci_dev *hdev,
1570 struct sock *sk, u8 val)
1571{
1572 bool changed = false;
1573 int err;
1574
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001575 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001576 changed = true;
1577
1578 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001579 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001580 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001581 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1582 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001583 }
1584
1585 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1586 if (err < 0)
1587 return err;
1588
Johan Hedberg562064e2014-07-08 16:35:34 +03001589 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001590 hci_req_update_scan(hdev);
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07001591 hci_update_passive_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001592 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001593 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001594
1595 return 0;
1596}
1597
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001598static int set_connectable_sync(struct hci_dev *hdev, void *data)
1599{
1600 BT_DBG("%s", hdev->name);
1601
1602 return hci_update_connectable_sync(hdev);
1603}
1604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001605static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001606 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001607{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001609 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001610 int err;
1611
Marcel Holtmann181d6952020-05-06 09:57:47 +02001612 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001613
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001614 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1615 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001616 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1617 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001618
Johan Hedberga7e80f22013-01-09 16:05:19 +02001619 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001620 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1621 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001622
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001623 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001624
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001625 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001626 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001627 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001628 }
1629
Johan Hedberg333ae952015-03-17 13:48:47 +02001630 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1631 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001632 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1633 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001634 goto failed;
1635 }
1636
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001637 cmd = mgmt_pending_new(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001638 if (!cmd) {
1639 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001640 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001641 }
1642
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001643 if (cp->val) {
1644 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1645 } else {
1646 if (hdev->discov_timeout > 0)
1647 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001648
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001649 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1650 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1651 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001652 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001653
Luiz Augusto von Dentzf056a652021-11-11 16:48:43 -08001654 err = hci_cmd_sync_queue(hdev, set_connectable_sync, cmd,
1655 mgmt_set_connectable_complete);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001656
1657failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001658 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001659 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001660}
1661
Johan Hedbergb2939472014-07-30 09:22:23 +03001662static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001663 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001664{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001665 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001666 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001667 int err;
1668
Marcel Holtmann181d6952020-05-06 09:57:47 +02001669 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001670
Johan Hedberga7e80f22013-01-09 16:05:19 +02001671 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001672 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1673 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001674
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001675 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001676
1677 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001678 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001679 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001680 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001681
Johan Hedbergb2939472014-07-30 09:22:23 +03001682 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001683 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001684 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001685
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001686 if (changed) {
1687 /* In limited privacy mode the change of bondable mode
1688 * may affect the local advertising address.
1689 */
Luiz Augusto von Dentz2bd1b232021-11-11 16:48:42 -08001690 hci_update_discoverable(hdev);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001691
Marcel Holtmann55594352013-10-06 16:11:57 -07001692 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001693 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001694
Marcel Holtmann55594352013-10-06 16:11:57 -07001695unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001696 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001697 return err;
1698}
1699
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001700static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1701 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001702{
1703 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001704 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001705 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001706 int err;
1707
Marcel Holtmann181d6952020-05-06 09:57:47 +02001708 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001709
Johan Hedberge6fe7982013-10-02 15:45:22 +03001710 status = mgmt_bredr_support(hdev);
1711 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001712 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1713 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001714
Johan Hedberga7e80f22013-01-09 16:05:19 +02001715 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001716 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1717 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001718
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001719 hci_dev_lock(hdev);
1720
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001721 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001722 bool changed = false;
1723
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001724 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001725 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001726 changed = true;
1727 }
1728
1729 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1730 if (err < 0)
1731 goto failed;
1732
1733 if (changed)
1734 err = new_settings(hdev, sk);
1735
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001736 goto failed;
1737 }
1738
Johan Hedberg333ae952015-03-17 13:48:47 +02001739 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001740 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1741 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001742 goto failed;
1743 }
1744
1745 val = !!cp->val;
1746
1747 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1748 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1749 goto failed;
1750 }
1751
1752 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1753 if (!cmd) {
1754 err = -ENOMEM;
1755 goto failed;
1756 }
1757
1758 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1759 if (err < 0) {
1760 mgmt_pending_remove(cmd);
1761 goto failed;
1762 }
1763
1764failed:
1765 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001766 return err;
1767}
1768
Brian Gix32448452021-10-27 16:58:58 -07001769static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
1770{
1771 struct cmd_lookup match = { NULL, hdev };
1772 struct mgmt_pending_cmd *cmd = data;
1773 struct mgmt_mode *cp = cmd->param;
1774 u8 enable = cp->val;
1775 bool changed;
1776
1777 if (err) {
1778 u8 mgmt_err = mgmt_status(err);
1779
1780 if (enable && hci_dev_test_and_clear_flag(hdev,
1781 HCI_SSP_ENABLED)) {
1782 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
1783 new_settings(hdev, NULL);
1784 }
1785
1786 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
1787 &mgmt_err);
1788 return;
1789 }
1790
1791 if (enable) {
1792 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
1793 } else {
1794 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
1795
1796 if (!changed)
1797 changed = hci_dev_test_and_clear_flag(hdev,
1798 HCI_HS_ENABLED);
1799 else
1800 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
1801 }
1802
1803 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
1804
1805 if (changed)
1806 new_settings(hdev, match.sk);
1807
1808 if (match.sk)
1809 sock_put(match.sk);
1810
1811 hci_update_eir_sync(hdev);
1812}
1813
1814static int set_ssp_sync(struct hci_dev *hdev, void *data)
1815{
1816 struct mgmt_pending_cmd *cmd = data;
1817 struct mgmt_mode *cp = cmd->param;
1818 bool changed = false;
1819 int err;
1820
1821 if (cp->val)
1822 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
1823
1824 err = hci_write_ssp_mode_sync(hdev, cp->val);
1825
1826 if (!err && changed)
1827 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
1828
1829 return err;
1830}
1831
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001832static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001833{
1834 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001835 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001836 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001837 int err;
1838
Marcel Holtmann181d6952020-05-06 09:57:47 +02001839 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001840
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001841 status = mgmt_bredr_support(hdev);
1842 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001843 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001844
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001845 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001846 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1847 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001848
Johan Hedberga7e80f22013-01-09 16:05:19 +02001849 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001850 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001852
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001853 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001854
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001855 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001856 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001857
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001858 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001859 changed = !hci_dev_test_and_set_flag(hdev,
1860 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001861 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001862 changed = hci_dev_test_and_clear_flag(hdev,
1863 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001864 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001865 changed = hci_dev_test_and_clear_flag(hdev,
1866 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001867 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001868 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001869 }
1870
1871 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1872 if (err < 0)
1873 goto failed;
1874
1875 if (changed)
1876 err = new_settings(hdev, sk);
1877
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001878 goto failed;
1879 }
1880
Johan Hedberg333ae952015-03-17 13:48:47 +02001881 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001882 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1883 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001884 goto failed;
1885 }
1886
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001887 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001888 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1889 goto failed;
1890 }
1891
1892 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
Brian Gix32448452021-10-27 16:58:58 -07001893 if (!cmd)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001894 err = -ENOMEM;
Brian Gix32448452021-10-27 16:58:58 -07001895 else
1896 err = hci_cmd_sync_queue(hdev, set_ssp_sync, cmd,
1897 set_ssp_complete);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001898
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001899 if (err < 0) {
Brian Gix32448452021-10-27 16:58:58 -07001900 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1901 MGMT_STATUS_FAILED);
1902
1903 if (cmd)
1904 mgmt_pending_remove(cmd);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001905 }
1906
1907failed:
1908 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001909 return err;
1910}
1911
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001912static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001913{
1914 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001915 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001916 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001917 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001918
Marcel Holtmann181d6952020-05-06 09:57:47 +02001919 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001920
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -07001921 if (!IS_ENABLED(CONFIG_BT_HS))
1922 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1923 MGMT_STATUS_NOT_SUPPORTED);
1924
Johan Hedberge6fe7982013-10-02 15:45:22 +03001925 status = mgmt_bredr_support(hdev);
1926 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001927 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001928
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001929 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1931 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001932
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001933 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001934 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1935 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001936
Johan Hedberga7e80f22013-01-09 16:05:19 +02001937 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001938 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1939 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001940
Marcel Holtmannee392692013-10-01 22:59:23 -07001941 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001942
Johan Hedberg333ae952015-03-17 13:48:47 +02001943 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001944 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1945 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001946 goto unlock;
1947 }
1948
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001949 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001950 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001951 } else {
1952 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001953 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1954 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001955 goto unlock;
1956 }
1957
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001958 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001959 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001960
1961 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1962 if (err < 0)
1963 goto unlock;
1964
1965 if (changed)
1966 err = new_settings(hdev, sk);
1967
1968unlock:
1969 hci_dev_unlock(hdev);
1970 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001971}
1972
Brian Gixd81a4942021-10-27 16:58:51 -07001973static void set_le_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001974{
1975 struct cmd_lookup match = { NULL, hdev };
Brian Gixd81a4942021-10-27 16:58:51 -07001976 u8 status = mgmt_status(err);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001977
Brian Gixd81a4942021-10-27 16:58:51 -07001978 bt_dev_dbg(hdev, "err %d", err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301979
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001980 if (status) {
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001981 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
Brian Gixd81a4942021-10-27 16:58:51 -07001982 &status);
1983 return;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001984 }
1985
1986 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1987
1988 new_settings(hdev, match.sk);
1989
1990 if (match.sk)
1991 sock_put(match.sk);
Brian Gixd81a4942021-10-27 16:58:51 -07001992}
1993
1994static int set_le_sync(struct hci_dev *hdev, void *data)
1995{
1996 struct mgmt_pending_cmd *cmd = data;
1997 struct mgmt_mode *cp = cmd->param;
1998 u8 val = !!cp->val;
1999 int err;
2000
2001 if (!val) {
2002 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
2003 hci_disable_advertising_sync(hdev);
2004
2005 if (ext_adv_capable(hdev))
2006 hci_remove_ext_adv_instance_sync(hdev, 0, cmd->sk);
2007 } else {
2008 hci_dev_set_flag(hdev, HCI_LE_ENABLED);
2009 }
2010
2011 err = hci_write_le_host_supported_sync(hdev, val, 0);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002012
2013 /* Make sure the controller has a good default for
2014 * advertising data. Restrict the update to when LE
2015 * has actually been enabled. During power on, the
2016 * update in powered_update_hci will take care of it.
2017 */
Brian Gixd81a4942021-10-27 16:58:51 -07002018 if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302019 if (ext_adv_capable(hdev)) {
Brian Gixd81a4942021-10-27 16:58:51 -07002020 int status;
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302021
Brian Gixd81a4942021-10-27 16:58:51 -07002022 status = hci_setup_ext_adv_instance_sync(hdev, 0x00);
2023 if (!status)
2024 hci_update_scan_rsp_data_sync(hdev, 0x00);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302025 } else {
Brian Gixd81a4942021-10-27 16:58:51 -07002026 hci_update_adv_data_sync(hdev, 0x00);
2027 hci_update_scan_rsp_data_sync(hdev, 0x00);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05302028 }
Brian Gixd81a4942021-10-27 16:58:51 -07002029
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07002030 hci_update_passive_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002031 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302032
Brian Gixd81a4942021-10-27 16:58:51 -07002033 return err;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002034}
2035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002036static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002037{
2038 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002039 struct mgmt_pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002040 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002041 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002042
Marcel Holtmann181d6952020-05-06 09:57:47 +02002043 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002044
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002045 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002046 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2047 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002048
Johan Hedberga7e80f22013-01-09 16:05:19 +02002049 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002050 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002052
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002053 /* Bluetooth single mode LE only controllers or dual-mode
2054 * controllers configured as LE only devices, do not allow
2055 * switching LE off. These have either LE enabled explicitly
2056 * or BR/EDR has been previously switched off.
2057 *
2058 * When trying to enable an already enabled LE, then gracefully
2059 * send a positive response. Trying to disable it however will
2060 * result into rejection.
2061 */
2062 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
2063 if (cp->val == 0x01)
2064 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2065
Johan Hedberga69e8372015-03-06 21:08:53 +02002066 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2067 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002068 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03002069
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002070 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002071
2072 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002073 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002074
Florian Grandel847818d2015-06-18 03:16:46 +02002075 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03002076 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02002077
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002078 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002079 bool changed = false;
2080
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002081 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002082 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002083 changed = true;
2084 }
2085
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002086 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002087 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002088 changed = true;
2089 }
2090
Johan Hedberg06199cf2012-02-22 16:37:11 +02002091 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2092 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002093 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002094
2095 if (changed)
2096 err = new_settings(hdev, sk);
2097
Johan Hedberg1de028c2012-02-29 19:55:35 -08002098 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002099 }
2100
Johan Hedberg333ae952015-03-17 13:48:47 +02002101 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2102 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002103 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2104 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002105 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002106 }
2107
2108 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
Brian Gixd81a4942021-10-27 16:58:51 -07002109 if (!cmd)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002110 err = -ENOMEM;
Brian Gixd81a4942021-10-27 16:58:51 -07002111 else
2112 err = hci_cmd_sync_queue(hdev, set_le_sync, cmd,
2113 set_le_complete);
2114
2115 if (err < 0) {
2116 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2117 MGMT_STATUS_FAILED);
2118
2119 if (cmd)
2120 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002121 }
2122
Johan Hedberg1de028c2012-02-29 19:55:35 -08002123unlock:
2124 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002125 return err;
2126}
2127
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002128/* This is a helper function to test for pending mgmt commands that can
2129 * cause CoD or EIR HCI commands. We can only allow one such pending
2130 * mgmt command at a time since otherwise we cannot easily track what
2131 * the current values are, will be, and based on that calculate if a new
2132 * HCI command needs to be sent and if yes with what value.
2133 */
2134static bool pending_eir_or_class(struct hci_dev *hdev)
2135{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002136 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002137
2138 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2139 switch (cmd->opcode) {
2140 case MGMT_OP_ADD_UUID:
2141 case MGMT_OP_REMOVE_UUID:
2142 case MGMT_OP_SET_DEV_CLASS:
2143 case MGMT_OP_SET_POWERED:
2144 return true;
2145 }
2146 }
2147
2148 return false;
2149}
2150
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002151static const u8 bluetooth_base_uuid[] = {
2152 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2153 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2154};
2155
2156static u8 get_uuid_size(const u8 *uuid)
2157{
2158 u32 val;
2159
2160 if (memcmp(uuid, bluetooth_base_uuid, 12))
2161 return 128;
2162
2163 val = get_unaligned_le32(&uuid[12]);
2164 if (val > 0xffff)
2165 return 32;
2166
2167 return 16;
2168}
2169
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002170static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg92da6092013-03-15 17:06:55 -05002171{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002172 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg92da6092013-03-15 17:06:55 -05002173
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002174 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg92da6092013-03-15 17:06:55 -05002175
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002176 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002177 mgmt_status(err), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002178
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002179 mgmt_pending_free(cmd);
Johan Hedberg92da6092013-03-15 17:06:55 -05002180}
2181
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002182static int add_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002183{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002184 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002185
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002186 err = hci_update_class_sync(hdev);
2187 if (err)
2188 return err;
2189
2190 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002191}
2192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002194{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002195 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002196 struct mgmt_pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002197 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002198 int err;
2199
Marcel Holtmann181d6952020-05-06 09:57:47 +02002200 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002202 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002203
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002204 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002205 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2206 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002207 goto failed;
2208 }
2209
Andre Guedes92c4c202012-06-07 19:05:44 -03002210 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002211 if (!uuid) {
2212 err = -ENOMEM;
2213 goto failed;
2214 }
2215
2216 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002217 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002218 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002219
Johan Hedbergde66aa62013-01-27 00:31:27 +02002220 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002221
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002222 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002223 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002224 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002225 goto failed;
2226 }
2227
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002228 err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete);
2229 if (err < 0) {
2230 mgmt_pending_free(cmd);
2231 goto failed;
2232 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002233
2234failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002235 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002236 return err;
2237}
2238
Johan Hedberg24b78d02012-02-23 23:24:30 +02002239static bool enable_service_cache(struct hci_dev *hdev)
2240{
2241 if (!hdev_is_powered(hdev))
2242 return false;
2243
Marcel Holtmann238be782015-03-13 02:11:06 -07002244 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002245 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2246 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002247 return true;
2248 }
2249
2250 return false;
2251}
2252
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002253static int remove_uuid_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002254{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002255 int err;
Johan Hedberg92da6092013-03-15 17:06:55 -05002256
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002257 err = hci_update_class_sync(hdev);
2258 if (err)
2259 return err;
2260
2261 return hci_update_eir_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002262}
2263
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002264static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002265 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002267 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002268 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002269 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002270 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 +02002271 int err, found;
2272
Marcel Holtmann181d6952020-05-06 09:57:47 +02002273 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002274
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002275 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002276
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002277 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002278 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2279 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002280 goto unlock;
2281 }
2282
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002283 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002284 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002285
Johan Hedberg24b78d02012-02-23 23:24:30 +02002286 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002287 err = mgmt_cmd_complete(sk, hdev->id,
2288 MGMT_OP_REMOVE_UUID,
2289 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002290 goto unlock;
2291 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002292
Johan Hedberg9246a862012-02-23 21:33:16 +02002293 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002294 }
2295
2296 found = 0;
2297
Johan Hedberg056341c2013-01-27 00:31:30 +02002298 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002299 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2300 continue;
2301
2302 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002303 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002304 found++;
2305 }
2306
2307 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002308 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002310 goto unlock;
2311 }
2312
Johan Hedberg9246a862012-02-23 21:33:16 +02002313update_class:
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002314 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002315 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002316 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002317 goto unlock;
2318 }
2319
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002320 err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd,
2321 mgmt_class_complete);
2322 if (err < 0)
2323 mgmt_pending_free(cmd);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002324
2325unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002326 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002327 return err;
2328}
2329
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002330static int set_class_sync(struct hci_dev *hdev, void *data)
Johan Hedberg92da6092013-03-15 17:06:55 -05002331{
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002332 int err = 0;
Johan Hedberg92da6092013-03-15 17:06:55 -05002333
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002334 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
2335 cancel_delayed_work_sync(&hdev->service_cache);
2336 err = hci_update_eir_sync(hdev);
2337 }
2338
2339 if (err)
2340 return err;
2341
2342 return hci_update_class_sync(hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002343}
2344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002345static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002347{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002348 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002349 struct mgmt_pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002350 int err;
2351
Marcel Holtmann181d6952020-05-06 09:57:47 +02002352 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002353
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002354 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002355 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2356 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002358 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002359
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002360 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002361 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2362 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002363 goto unlock;
2364 }
2365
2366 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002367 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2368 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002369 goto unlock;
2370 }
2371
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002372 hdev->major_class = cp->major;
2373 hdev->minor_class = cp->minor;
2374
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002375 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002376 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2377 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002378 goto unlock;
2379 }
2380
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002381 cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002382 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002383 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002384 goto unlock;
2385 }
2386
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07002387 err = hci_cmd_sync_queue(hdev, set_class_sync, cmd,
2388 mgmt_class_complete);
2389 if (err < 0)
2390 mgmt_pending_free(cmd);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002391
Johan Hedbergb5235a62012-02-21 14:32:24 +02002392unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002393 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002394 return err;
2395}
2396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002397static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002398 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002399{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002400 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002401 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2402 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002403 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002404 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002405 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002406
Marcel Holtmann181d6952020-05-06 09:57:47 +02002407 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002408
2409 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002410 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2411 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002412
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002413 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002414 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002415 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2416 key_count);
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 Hedbergba1d6932014-07-03 13:52:27 +03002419 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002420
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002421 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002422 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002423 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2424 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002425 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2426 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002427 }
2428
Johan Hedberg4ae143012013-01-20 14:27:13 +02002429 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002430 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2431 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002432
Marcel Holtmann181d6952020-05-06 09:57:47 +02002433 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2434 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002435
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002436 for (i = 0; i < key_count; i++) {
2437 struct mgmt_link_key_info *key = &cp->keys[i];
2438
Marcel Holtmann8e991132014-01-10 02:07:25 -08002439 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002440 return mgmt_cmd_status(sk, hdev->id,
2441 MGMT_OP_LOAD_LINK_KEYS,
2442 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002443 }
2444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002446
2447 hci_link_keys_clear(hdev);
2448
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002449 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002450 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002451 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002452 changed = hci_dev_test_and_clear_flag(hdev,
2453 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002454
2455 if (changed)
2456 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002457
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002458 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002459 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002460
Alain Michaud600a8742020-01-07 00:43:17 +00002461 if (hci_is_blocked_key(hdev,
2462 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2463 key->val)) {
2464 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2465 &key->addr.bdaddr);
2466 continue;
2467 }
2468
Johan Hedberg58e92932014-06-24 14:00:26 +03002469 /* Always ignore debug keys and require a new pairing if
2470 * the user wants to use them.
2471 */
2472 if (key->type == HCI_LK_DEBUG_COMBINATION)
2473 continue;
2474
Johan Hedberg7652ff62014-06-24 13:15:49 +03002475 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2476 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002477 }
2478
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002479 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002480
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002481 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002482
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002483 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002484}
2485
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002486static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002487 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002488{
2489 struct mgmt_ev_device_unpaired ev;
2490
2491 bacpy(&ev.addr.bdaddr, bdaddr);
2492 ev.addr.type = addr_type;
2493
2494 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002495 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002496}
2497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002500{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002501 struct mgmt_cp_unpair_device *cp = data;
2502 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002503 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002504 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002505 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002506 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002507 int err;
2508
Johan Hedberga8a1d192011-11-10 15:54:38 +02002509 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002510 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2511 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002512
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002513 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002514 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2515 MGMT_STATUS_INVALID_PARAMS,
2516 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002517
Johan Hedberg118da702013-01-20 14:27:20 +02002518 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002519 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2520 MGMT_STATUS_INVALID_PARAMS,
2521 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002522
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002523 hci_dev_lock(hdev);
2524
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002525 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002526 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2527 MGMT_STATUS_NOT_POWERED, &rp,
2528 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002529 goto unlock;
2530 }
2531
Johan Hedberge0b2b272014-02-18 17:14:31 +02002532 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002533 /* If disconnection is requested, then look up the
2534 * connection. If the remote device is connected, it
2535 * will be later used to terminate the link.
2536 *
2537 * Setting it to NULL explicitly will cause no
2538 * termination of the link.
2539 */
2540 if (cp->disconnect)
2541 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2542 &cp->addr.bdaddr);
2543 else
2544 conn = NULL;
2545
Johan Hedberg124f6e32012-02-09 13:50:12 +02002546 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002547 if (err < 0) {
2548 err = mgmt_cmd_complete(sk, hdev->id,
2549 MGMT_OP_UNPAIR_DEVICE,
2550 MGMT_STATUS_NOT_PAIRED, &rp,
2551 sizeof(rp));
2552 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002553 }
2554
Johan Hedbergec182f02015-10-21 18:03:03 +03002555 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002556 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002557
Johan Hedbergec182f02015-10-21 18:03:03 +03002558 /* LE address type */
2559 addr_type = le_addr_type(cp->addr.type);
2560
Matias Karhumaacb28c302018-09-26 09:13:46 +03002561 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2562 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002563 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002564 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2565 MGMT_STATUS_NOT_PAIRED, &rp,
2566 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002567 goto unlock;
2568 }
2569
Johan Hedbergec182f02015-10-21 18:03:03 +03002570 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2571 if (!conn) {
2572 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2573 goto done;
2574 }
2575
Johan Hedbergc81d5552015-10-22 09:38:35 +03002576
Johan Hedbergec182f02015-10-21 18:03:03 +03002577 /* Defer clearing up the connection parameters until closing to
2578 * give a chance of keeping them if a repairing happens.
2579 */
2580 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2581
Johan Hedbergfc643612015-10-22 09:38:31 +03002582 /* Disable auto-connection parameters if present */
2583 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2584 if (params) {
2585 if (params->explicit_connect)
2586 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2587 else
2588 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2589 }
2590
Johan Hedbergec182f02015-10-21 18:03:03 +03002591 /* If disconnection is not requested, then clear the connection
2592 * variable so that the link is not terminated.
2593 */
2594 if (!cp->disconnect)
2595 conn = NULL;
2596
2597done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002598 /* If the connection variable is set, then termination of the
2599 * link is requested.
2600 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002601 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002602 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2603 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002604 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002605 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002606 }
2607
Johan Hedberg124f6e32012-02-09 13:50:12 +02002608 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002610 if (!cmd) {
2611 err = -ENOMEM;
2612 goto unlock;
2613 }
2614
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002615 cmd->cmd_complete = addr_cmd_complete;
2616
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002617 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002618 if (err < 0)
2619 mgmt_pending_remove(cmd);
2620
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002621unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002622 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002623 return err;
2624}
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002628{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002629 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002630 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002631 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002632 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002633 int err;
2634
Marcel Holtmann181d6952020-05-06 09:57:47 +02002635 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002636
Johan Hedberg06a63b12013-01-20 14:27:21 +02002637 memset(&rp, 0, sizeof(rp));
2638 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2639 rp.addr.type = cp->addr.type;
2640
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002641 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002642 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2643 MGMT_STATUS_INVALID_PARAMS,
2644 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002645
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002646 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002647
2648 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002649 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2650 MGMT_STATUS_NOT_POWERED, &rp,
2651 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002652 goto failed;
2653 }
2654
Johan Hedberg333ae952015-03-17 13:48:47 +02002655 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002656 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2657 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002658 goto failed;
2659 }
2660
Andre Guedes591f47f2012-04-24 21:02:49 -03002661 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002662 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2663 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002664 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002665 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2666 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002667
Vishal Agarwalf9607272012-06-13 05:32:43 +05302668 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002669 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2670 MGMT_STATUS_NOT_CONNECTED, &rp,
2671 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002672 goto failed;
2673 }
2674
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002675 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002676 if (!cmd) {
2677 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002678 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002679 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002680
Johan Hedbergf5818c22014-12-05 13:36:02 +02002681 cmd->cmd_complete = generic_cmd_complete;
2682
Johan Hedberge3f2f922014-08-18 20:33:33 +03002683 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002684 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002685 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002686
2687failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002688 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002689 return err;
2690}
2691
Andre Guedes57c14772012-04-24 21:02:50 -03002692static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002693{
2694 switch (link_type) {
2695 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002696 switch (addr_type) {
2697 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002698 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002699
Johan Hedberg48264f02011-11-09 13:58:58 +02002700 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002701 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002702 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002703 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002704
Johan Hedberg4c659c32011-11-07 23:13:39 +02002705 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002706 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002707 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002708 }
2709}
2710
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2712 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002713{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002714 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002715 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002716 int err;
2717 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002718
Marcel Holtmann181d6952020-05-06 09:57:47 +02002719 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002720
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002721 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002722
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002723 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002724 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2725 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002726 goto unlock;
2727 }
2728
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002729 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002730 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2731 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002732 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002733 }
2734
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002735 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002736 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002737 err = -ENOMEM;
2738 goto unlock;
2739 }
2740
Johan Hedberg2784eb42011-01-21 13:56:35 +02002741 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002742 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002743 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2744 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002745 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002746 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002747 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002748 continue;
2749 i++;
2750 }
2751
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002752 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002753
Johan Hedberg4c659c32011-11-07 23:13:39 +02002754 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002755 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002756 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002757
Johan Hedberga38528f2011-01-22 06:46:43 +02002758 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002759
2760unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002762 return err;
2763}
2764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002765static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002767{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002768 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002769 int err;
2770
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002771 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002772 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002773 if (!cmd)
2774 return -ENOMEM;
2775
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002776 cmd->cmd_complete = addr_cmd_complete;
2777
Johan Hedbergd8457692012-02-17 14:24:57 +02002778 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002780 if (err < 0)
2781 mgmt_pending_remove(cmd);
2782
2783 return err;
2784}
2785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002786static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002787 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002788{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002789 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002791 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002792 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002793 int err;
2794
Marcel Holtmann181d6952020-05-06 09:57:47 +02002795 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002797 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002798
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002799 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002800 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2801 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002802 goto failed;
2803 }
2804
Johan Hedbergd8457692012-02-17 14:24:57 +02002805 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002806 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002807 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2808 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002809 goto failed;
2810 }
2811
2812 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002813 struct mgmt_cp_pin_code_neg_reply ncp;
2814
2815 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002816
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002817 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002819 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002820 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002821 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2822 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002823
2824 goto failed;
2825 }
2826
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002827 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002828 if (!cmd) {
2829 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002830 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002831 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002832
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002833 cmd->cmd_complete = addr_cmd_complete;
2834
Johan Hedbergd8457692012-02-17 14:24:57 +02002835 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002836 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002837 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002838
2839 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2840 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002841 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002842
2843failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002844 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002845 return err;
2846}
2847
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2849 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002850{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002851 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002852
Marcel Holtmann181d6952020-05-06 09:57:47 +02002853 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002854
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002855 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002856 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2857 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002858
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002859 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002860
2861 hdev->io_capability = cp->io_capability;
2862
Marcel Holtmann181d6952020-05-06 09:57:47 +02002863 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002865 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002866
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002867 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2868 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002869}
2870
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002871static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872{
2873 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002874 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002875
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002876 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002877 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2878 continue;
2879
Johan Hedberge9a416b2011-02-19 12:05:56 -03002880 if (cmd->user_data != conn)
2881 continue;
2882
2883 return cmd;
2884 }
2885
2886 return NULL;
2887}
2888
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002889static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002890{
2891 struct mgmt_rp_pair_device rp;
2892 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002893 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002894
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002895 bacpy(&rp.addr.bdaddr, &conn->dst);
2896 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002897
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002898 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2899 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002900
2901 /* So we don't get further callbacks for this connection */
2902 conn->connect_cfm_cb = NULL;
2903 conn->security_cfm_cb = NULL;
2904 conn->disconn_cfm_cb = NULL;
2905
David Herrmann76a68ba2013-04-06 20:28:37 +02002906 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002907
2908 /* The device is paired so there is no need to remove
2909 * its connection parameters anymore.
2910 */
2911 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002912
2913 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002914
2915 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002916}
2917
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002918void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2919{
2920 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002921 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002922
2923 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002924 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002925 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002926 mgmt_pending_remove(cmd);
2927 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002928}
2929
Johan Hedberge9a416b2011-02-19 12:05:56 -03002930static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2931{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002932 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002933
2934 BT_DBG("status %u", status);
2935
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002936 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002937 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002938 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002939 return;
2940 }
2941
2942 cmd->cmd_complete(cmd, mgmt_status(status));
2943 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002944}
2945
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002946static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302947{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002948 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302949
2950 BT_DBG("status %u", status);
2951
2952 if (!status)
2953 return;
2954
2955 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002956 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302957 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002958 return;
2959 }
2960
2961 cmd->cmd_complete(cmd, mgmt_status(status));
2962 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302963}
2964
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002965static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002966 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002967{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002969 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002970 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002971 u8 sec_level, auth_type;
2972 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002973 int err;
2974
Marcel Holtmann181d6952020-05-06 09:57:47 +02002975 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002976
Szymon Jancf950a30e2013-01-18 12:48:07 +01002977 memset(&rp, 0, sizeof(rp));
2978 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2979 rp.addr.type = cp->addr.type;
2980
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002981 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002982 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2983 MGMT_STATUS_INVALID_PARAMS,
2984 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002985
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002986 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002987 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2988 MGMT_STATUS_INVALID_PARAMS,
2989 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002992
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002993 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002994 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2995 MGMT_STATUS_NOT_POWERED, &rp,
2996 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002997 goto unlock;
2998 }
2999
Johan Hedberg55e76b32015-03-10 22:34:40 +02003000 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3001 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3002 MGMT_STATUS_ALREADY_PAIRED, &rp,
3003 sizeof(rp));
3004 goto unlock;
3005 }
3006
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003007 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003008 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003009
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003010 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003011 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02003012 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003013 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03003014 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003015 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003016
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003017 /* When pairing a new device, it is expected to remember
3018 * this device for future connections. Adding the connection
3019 * parameter information ahead of time allows tracking
Archie Pusaka67ffb182021-05-31 16:37:28 +08003020 * of the peripheral preferred values and will speed up any
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003021 * further connection establishment.
3022 *
3023 * If connection parameters already exist, then they
3024 * will be kept and this function does nothing.
3025 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003026 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3027
3028 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
3029 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003030
Manish Mandlik76b13992020-06-17 16:39:19 +02003031 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
3032 sec_level, HCI_LE_CONN_TIMEOUT,
3033 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003034 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003035
Ville Tervo30e76272011-02-22 16:10:53 -03003036 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003037 int status;
3038
3039 if (PTR_ERR(conn) == -EBUSY)
3040 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003041 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3042 status = MGMT_STATUS_NOT_SUPPORTED;
3043 else if (PTR_ERR(conn) == -ECONNREFUSED)
3044 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003045 else
3046 status = MGMT_STATUS_CONNECT_FAILED;
3047
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003048 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3049 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003050 goto unlock;
3051 }
3052
3053 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003054 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003055 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3056 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003057 goto unlock;
3058 }
3059
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003060 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003061 if (!cmd) {
3062 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003063 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003064 goto unlock;
3065 }
3066
Johan Hedberg04ab2742014-12-05 13:36:04 +02003067 cmd->cmd_complete = pairing_complete;
3068
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003069 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003070 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003071 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003072 conn->security_cfm_cb = pairing_complete_cb;
3073 conn->disconn_cfm_cb = pairing_complete_cb;
3074 } else {
3075 conn->connect_cfm_cb = le_pairing_complete_cb;
3076 conn->security_cfm_cb = le_pairing_complete_cb;
3077 conn->disconn_cfm_cb = le_pairing_complete_cb;
3078 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003079
Johan Hedberge9a416b2011-02-19 12:05:56 -03003080 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003081 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003082
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003083 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003084 hci_conn_security(conn, sec_level, auth_type, true)) {
3085 cmd->cmd_complete(cmd, 0);
3086 mgmt_pending_remove(cmd);
3087 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003088
3089 err = 0;
3090
3091unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003092 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003093 return err;
3094}
3095
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3097 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003098{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003099 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003100 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003101 struct hci_conn *conn;
3102 int err;
3103
Marcel Holtmann181d6952020-05-06 09:57:47 +02003104 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003105
Johan Hedberg28424702012-02-02 04:02:29 +02003106 hci_dev_lock(hdev);
3107
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003108 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003109 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3110 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003111 goto unlock;
3112 }
3113
Johan Hedberg333ae952015-03-17 13:48:47 +02003114 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003115 if (!cmd) {
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
3121 conn = cmd->user_data;
3122
3123 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003124 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3125 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003126 goto unlock;
3127 }
3128
Johan Hedberga511b352014-12-11 21:45:45 +02003129 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3130 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003131
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003132 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3133 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003134
3135 /* Since user doesn't want to proceed with the connection, abort any
3136 * ongoing pairing and then terminate the link if it was created
3137 * because of the pair device action.
3138 */
3139 if (addr->type == BDADDR_BREDR)
3140 hci_remove_link_key(hdev, &addr->bdaddr);
3141 else
3142 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3143 le_addr_type(addr->type));
3144
3145 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3146 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3147
Johan Hedberg28424702012-02-02 04:02:29 +02003148unlock:
3149 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003150 return err;
3151}
3152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003153static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003154 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003155 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003156{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003157 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003158 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003159 int err;
3160
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003161 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003162
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003163 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003164 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3165 MGMT_STATUS_NOT_POWERED, addr,
3166 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003167 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003168 }
3169
Johan Hedberg1707c602013-03-15 17:07:15 -05003170 if (addr->type == BDADDR_BREDR)
3171 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003173 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3174 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003175
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003177 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3178 MGMT_STATUS_NOT_CONNECTED, addr,
3179 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003180 goto done;
3181 }
3182
Johan Hedberg1707c602013-03-15 17:07:15 -05003183 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003184 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003185 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003186 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3187 MGMT_STATUS_SUCCESS, addr,
3188 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003189 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003190 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3191 MGMT_STATUS_FAILED, addr,
3192 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003193
Brian Gix47c15e22011-11-16 13:53:14 -08003194 goto done;
3195 }
3196
Johan Hedberg1707c602013-03-15 17:07:15 -05003197 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003198 if (!cmd) {
3199 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003200 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003201 }
3202
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003203 cmd->cmd_complete = addr_cmd_complete;
3204
Brian Gix0df4c182011-11-16 13:53:13 -08003205 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003206 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3207 struct hci_cp_user_passkey_reply cp;
3208
Johan Hedberg1707c602013-03-15 17:07:15 -05003209 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003210 cp.passkey = passkey;
3211 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3212 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003213 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3214 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003215
Johan Hedberga664b5b2011-02-19 12:06:02 -03003216 if (err < 0)
3217 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003218
Brian Gix0df4c182011-11-16 13:53:13 -08003219done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003220 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003221 return err;
3222}
3223
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303224static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3225 void *data, u16 len)
3226{
3227 struct mgmt_cp_pin_code_neg_reply *cp = data;
3228
Marcel Holtmann181d6952020-05-06 09:57:47 +02003229 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303230
Johan Hedberg1707c602013-03-15 17:07:15 -05003231 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303232 MGMT_OP_PIN_CODE_NEG_REPLY,
3233 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3234}
3235
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003236static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3237 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003238{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003239 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003240
Marcel Holtmann181d6952020-05-06 09:57:47 +02003241 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003242
3243 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003244 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3245 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003246
Johan Hedberg1707c602013-03-15 17:07:15 -05003247 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003248 MGMT_OP_USER_CONFIRM_REPLY,
3249 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003250}
3251
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003252static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003253 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003254{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003255 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003256
Marcel Holtmann181d6952020-05-06 09:57:47 +02003257 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003258
Johan Hedberg1707c602013-03-15 17:07:15 -05003259 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003260 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3261 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003262}
3263
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003264static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3265 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003267 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003268
Marcel Holtmann181d6952020-05-06 09:57:47 +02003269 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003270
Johan Hedberg1707c602013-03-15 17:07:15 -05003271 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003272 MGMT_OP_USER_PASSKEY_REPLY,
3273 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003274}
3275
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003276static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003277 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003278{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003279 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003280
Marcel Holtmann181d6952020-05-06 09:57:47 +02003281 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003282
Johan Hedberg1707c602013-03-15 17:07:15 -05003283 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003284 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3285 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003286}
3287
Brian Gix5e233ed2021-10-27 16:58:57 -07003288static int adv_expire_sync(struct hci_dev *hdev, u32 flags)
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003289{
3290 struct adv_info *adv_instance;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003291
3292 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3293 if (!adv_instance)
Brian Gix5e233ed2021-10-27 16:58:57 -07003294 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003295
3296 /* stop if current instance doesn't need to be changed */
3297 if (!(adv_instance->flags & flags))
Brian Gix5e233ed2021-10-27 16:58:57 -07003298 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003299
3300 cancel_adv_timeout(hdev);
3301
3302 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3303 if (!adv_instance)
Brian Gix5e233ed2021-10-27 16:58:57 -07003304 return 0;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003305
Brian Gix5e233ed2021-10-27 16:58:57 -07003306 hci_schedule_adv_instance_sync(hdev, adv_instance->instance, true);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003307
Brian Gix5e233ed2021-10-27 16:58:57 -07003308 return 0;
3309}
3310
3311static int name_changed_sync(struct hci_dev *hdev, void *data)
3312{
3313 return adv_expire_sync(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003314}
3315
Brian Gix6f6ff382021-10-27 16:58:54 -07003316static void set_name_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg13928972013-03-15 17:07:00 -05003317{
Brian Gix6f6ff382021-10-27 16:58:54 -07003318 struct mgmt_pending_cmd *cmd = data;
3319 struct mgmt_cp_set_local_name *cp = cmd->param;
3320 u8 status = mgmt_status(err);
Johan Hedberg13928972013-03-15 17:07:00 -05003321
Brian Gix6f6ff382021-10-27 16:58:54 -07003322 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg13928972013-03-15 17:07:00 -05003323
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003324 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003325 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Brian Gix6f6ff382021-10-27 16:58:54 -07003326 status);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003327 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003328 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3329 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003330
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003331 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Brian Gix5e233ed2021-10-27 16:58:57 -07003332 hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003333 }
3334
Johan Hedberg13928972013-03-15 17:07:00 -05003335 mgmt_pending_remove(cmd);
Brian Gix6f6ff382021-10-27 16:58:54 -07003336}
Johan Hedberg13928972013-03-15 17:07:00 -05003337
Brian Gix6f6ff382021-10-27 16:58:54 -07003338static int set_name_sync(struct hci_dev *hdev, void *data)
3339{
3340 if (lmp_bredr_capable(hdev)) {
3341 hci_update_name_sync(hdev);
3342 hci_update_eir_sync(hdev);
3343 }
3344
3345 /* The name is stored in the scan response data and so
3346 * no need to update the advertising data here.
3347 */
3348 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
3349 hci_update_scan_rsp_data_sync(hdev, hdev->cur_adv_instance);
3350
3351 return 0;
Johan Hedberg13928972013-03-15 17:07:00 -05003352}
3353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003354static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003355 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003356{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003357 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003358 struct mgmt_pending_cmd *cmd;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003359 int err;
3360
Marcel Holtmann181d6952020-05-06 09:57:47 +02003361 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003363 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003364
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003365 /* If the old values are the same as the new ones just return a
3366 * direct command complete event.
3367 */
3368 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3369 !memcmp(hdev->short_name, cp->short_name,
3370 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003371 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3372 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003373 goto failed;
3374 }
3375
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003376 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003377
Johan Hedbergb5235a62012-02-21 14:32:24 +02003378 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003379 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003380
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003381 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3382 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003383 if (err < 0)
3384 goto failed;
3385
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003386 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3387 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003388 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003389
Johan Hedbergb5235a62012-02-21 14:32:24 +02003390 goto failed;
3391 }
3392
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003393 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Brian Gix6f6ff382021-10-27 16:58:54 -07003394 if (!cmd)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003395 err = -ENOMEM;
Brian Gix6f6ff382021-10-27 16:58:54 -07003396 else
3397 err = hci_cmd_sync_queue(hdev, set_name_sync, cmd,
3398 set_name_complete);
3399
3400 if (err < 0) {
3401 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3402 MGMT_STATUS_FAILED);
3403
3404 if (cmd)
3405 mgmt_pending_remove(cmd);
3406
Johan Hedbergb312b1612011-03-16 14:29:37 +02003407 goto failed;
3408 }
3409
Johan Hedberg13928972013-03-15 17:07:00 -05003410 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3411
Johan Hedbergb312b1612011-03-16 14:29:37 +02003412failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003413 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003414 return err;
3415}
3416
Brian Gix5e233ed2021-10-27 16:58:57 -07003417static int appearance_changed_sync(struct hci_dev *hdev, void *data)
3418{
3419 return adv_expire_sync(hdev, MGMT_ADV_FLAG_APPEARANCE);
3420}
3421
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003422static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3423 u16 len)
3424{
3425 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003426 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003427 int err;
3428
Marcel Holtmann181d6952020-05-06 09:57:47 +02003429 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003430
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003431 if (!lmp_le_capable(hdev))
3432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3433 MGMT_STATUS_NOT_SUPPORTED);
3434
Alain Michaud6613bab2020-01-22 19:47:44 +00003435 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003436
3437 hci_dev_lock(hdev);
3438
Alain Michaud6613bab2020-01-22 19:47:44 +00003439 if (hdev->appearance != appearance) {
3440 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003441
3442 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Brian Gix5e233ed2021-10-27 16:58:57 -07003443 hci_cmd_sync_queue(hdev, appearance_changed_sync, NULL,
3444 NULL);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003445
3446 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003447 }
3448
3449 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3450 0);
3451
3452 hci_dev_unlock(hdev);
3453
3454 return err;
3455}
3456
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303457static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3458 void *data, u16 len)
3459{
Reo Shiseki353021582020-11-19 16:37:11 +09003460 struct mgmt_rp_get_phy_configuration rp;
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303461
Marcel Holtmann181d6952020-05-06 09:57:47 +02003462 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303463
3464 hci_dev_lock(hdev);
3465
3466 memset(&rp, 0, sizeof(rp));
3467
3468 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3469 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3470 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3471
3472 hci_dev_unlock(hdev);
3473
3474 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3475 &rp, sizeof(rp));
3476}
3477
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303478int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3479{
3480 struct mgmt_ev_phy_configuration_changed ev;
3481
3482 memset(&ev, 0, sizeof(ev));
3483
3484 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3485
3486 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3487 sizeof(ev), skip);
3488}
3489
Brian Gix71efbb02021-10-27 16:58:55 -07003490static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303491{
Brian Gix71efbb02021-10-27 16:58:55 -07003492 struct mgmt_pending_cmd *cmd = data;
3493 struct sk_buff *skb = cmd->skb;
3494 u8 status = mgmt_status(err);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303495
Brian Gix71efbb02021-10-27 16:58:55 -07003496 if (!status) {
3497 if (!skb)
3498 status = MGMT_STATUS_FAILED;
3499 else if (IS_ERR(skb))
3500 status = mgmt_status(PTR_ERR(skb));
3501 else
3502 status = mgmt_status(skb->data[0]);
3503 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303504
Brian Gix71efbb02021-10-27 16:58:55 -07003505 bt_dev_dbg(hdev, "status %d", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303506
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303507 if (status) {
3508 mgmt_cmd_status(cmd->sk, hdev->id,
Brian Gix71efbb02021-10-27 16:58:55 -07003509 MGMT_OP_SET_PHY_CONFIGURATION, status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303510 } else {
3511 mgmt_cmd_complete(cmd->sk, hdev->id,
3512 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3513 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303514
3515 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303516 }
3517
Brian Gix71efbb02021-10-27 16:58:55 -07003518 if (skb && !IS_ERR(skb))
3519 kfree_skb(skb);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303520
Brian Gix71efbb02021-10-27 16:58:55 -07003521 mgmt_pending_remove(cmd);
3522}
3523
3524static int set_default_phy_sync(struct hci_dev *hdev, void *data)
3525{
3526 struct mgmt_pending_cmd *cmd = data;
3527 struct mgmt_cp_set_phy_configuration *cp = cmd->param;
3528 struct hci_cp_le_set_default_phy cp_phy;
3529 u32 selected_phys = __le32_to_cpu(cp->selected_phys);
3530
3531 memset(&cp_phy, 0, sizeof(cp_phy));
3532
3533 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3534 cp_phy.all_phys |= 0x01;
3535
3536 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3537 cp_phy.all_phys |= 0x02;
3538
3539 if (selected_phys & MGMT_PHY_LE_1M_TX)
3540 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3541
3542 if (selected_phys & MGMT_PHY_LE_2M_TX)
3543 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3544
3545 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3546 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3547
3548 if (selected_phys & MGMT_PHY_LE_1M_RX)
3549 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3550
3551 if (selected_phys & MGMT_PHY_LE_2M_RX)
3552 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3553
3554 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3555 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3556
3557 cmd->skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_DEFAULT_PHY,
3558 sizeof(cp_phy), &cp_phy, HCI_CMD_TIMEOUT);
3559
3560 return 0;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303561}
3562
3563static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3564 void *data, u16 len)
3565{
Reo Shiseki353021582020-11-19 16:37:11 +09003566 struct mgmt_cp_set_phy_configuration *cp = data;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303567 struct mgmt_pending_cmd *cmd;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303568 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3569 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303570 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303571 int err;
3572
Marcel Holtmann181d6952020-05-06 09:57:47 +02003573 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303574
3575 configurable_phys = get_configurable_phys(hdev);
3576 supported_phys = get_supported_phys(hdev);
3577 selected_phys = __le32_to_cpu(cp->selected_phys);
3578
3579 if (selected_phys & ~supported_phys)
3580 return mgmt_cmd_status(sk, hdev->id,
3581 MGMT_OP_SET_PHY_CONFIGURATION,
3582 MGMT_STATUS_INVALID_PARAMS);
3583
3584 unconfigure_phys = supported_phys & ~configurable_phys;
3585
3586 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3587 return mgmt_cmd_status(sk, hdev->id,
3588 MGMT_OP_SET_PHY_CONFIGURATION,
3589 MGMT_STATUS_INVALID_PARAMS);
3590
3591 if (selected_phys == get_selected_phys(hdev))
3592 return mgmt_cmd_complete(sk, hdev->id,
3593 MGMT_OP_SET_PHY_CONFIGURATION,
3594 0, NULL, 0);
3595
3596 hci_dev_lock(hdev);
3597
3598 if (!hdev_is_powered(hdev)) {
3599 err = mgmt_cmd_status(sk, hdev->id,
3600 MGMT_OP_SET_PHY_CONFIGURATION,
3601 MGMT_STATUS_REJECTED);
3602 goto unlock;
3603 }
3604
3605 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3606 err = mgmt_cmd_status(sk, hdev->id,
3607 MGMT_OP_SET_PHY_CONFIGURATION,
3608 MGMT_STATUS_BUSY);
3609 goto unlock;
3610 }
3611
3612 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3613 pkt_type |= (HCI_DH3 | HCI_DM3);
3614 else
3615 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3616
3617 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3618 pkt_type |= (HCI_DH5 | HCI_DM5);
3619 else
3620 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3621
3622 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3623 pkt_type &= ~HCI_2DH1;
3624 else
3625 pkt_type |= HCI_2DH1;
3626
3627 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3628 pkt_type &= ~HCI_2DH3;
3629 else
3630 pkt_type |= HCI_2DH3;
3631
3632 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3633 pkt_type &= ~HCI_2DH5;
3634 else
3635 pkt_type |= HCI_2DH5;
3636
3637 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3638 pkt_type &= ~HCI_3DH1;
3639 else
3640 pkt_type |= HCI_3DH1;
3641
3642 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3643 pkt_type &= ~HCI_3DH3;
3644 else
3645 pkt_type |= HCI_3DH3;
3646
3647 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3648 pkt_type &= ~HCI_3DH5;
3649 else
3650 pkt_type |= HCI_3DH5;
3651
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303652 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303653 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303654 changed = true;
3655 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303656
3657 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3658 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303659 if (changed)
3660 mgmt_phy_configuration_changed(hdev, sk);
3661
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303662 err = mgmt_cmd_complete(sk, hdev->id,
3663 MGMT_OP_SET_PHY_CONFIGURATION,
3664 0, NULL, 0);
3665
3666 goto unlock;
3667 }
3668
3669 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3670 len);
Brian Gix71efbb02021-10-27 16:58:55 -07003671 if (!cmd)
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303672 err = -ENOMEM;
Brian Gix71efbb02021-10-27 16:58:55 -07003673 else
3674 err = hci_cmd_sync_queue(hdev, set_default_phy_sync, cmd,
3675 set_default_phy_complete);
3676
3677 if (err < 0) {
3678 err = mgmt_cmd_status(sk, hdev->id,
3679 MGMT_OP_SET_PHY_CONFIGURATION,
3680 MGMT_STATUS_FAILED);
3681
3682 if (cmd)
3683 mgmt_pending_remove(cmd);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303684 }
3685
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303686unlock:
3687 hci_dev_unlock(hdev);
3688
3689 return err;
3690}
3691
Alain Michaud600a8742020-01-07 00:43:17 +00003692static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3693 u16 len)
3694{
3695 int err = MGMT_STATUS_SUCCESS;
3696 struct mgmt_cp_set_blocked_keys *keys = data;
3697 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3698 sizeof(struct mgmt_blocked_key_info));
3699 u16 key_count, expected_len;
3700 int i;
3701
Marcel Holtmann181d6952020-05-06 09:57:47 +02003702 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003703
3704 key_count = __le16_to_cpu(keys->key_count);
3705 if (key_count > max_key_count) {
3706 bt_dev_err(hdev, "too big key_count value %u", key_count);
3707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3708 MGMT_STATUS_INVALID_PARAMS);
3709 }
3710
3711 expected_len = struct_size(keys, keys, key_count);
3712 if (expected_len != len) {
3713 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3714 expected_len, len);
3715 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3716 MGMT_STATUS_INVALID_PARAMS);
3717 }
3718
3719 hci_dev_lock(hdev);
3720
3721 hci_blocked_keys_clear(hdev);
3722
3723 for (i = 0; i < keys->key_count; ++i) {
3724 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3725
3726 if (!b) {
3727 err = MGMT_STATUS_NO_RESOURCES;
3728 break;
3729 }
3730
3731 b->type = keys->keys[i].type;
3732 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3733 list_add_rcu(&b->list, &hdev->blocked_keys);
3734 }
3735 hci_dev_unlock(hdev);
3736
3737 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3738 err, NULL, 0);
3739}
3740
Alain Michaud00bce3f2020-03-05 16:14:59 +00003741static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3742 void *data, u16 len)
3743{
3744 struct mgmt_mode *cp = data;
3745 int err;
3746 bool changed = false;
3747
Marcel Holtmann181d6952020-05-06 09:57:47 +02003748 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003749
3750 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3751 return mgmt_cmd_status(sk, hdev->id,
3752 MGMT_OP_SET_WIDEBAND_SPEECH,
3753 MGMT_STATUS_NOT_SUPPORTED);
3754
3755 if (cp->val != 0x00 && cp->val != 0x01)
3756 return mgmt_cmd_status(sk, hdev->id,
3757 MGMT_OP_SET_WIDEBAND_SPEECH,
3758 MGMT_STATUS_INVALID_PARAMS);
3759
3760 hci_dev_lock(hdev);
3761
3762 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3763 err = mgmt_cmd_status(sk, hdev->id,
3764 MGMT_OP_SET_WIDEBAND_SPEECH,
3765 MGMT_STATUS_BUSY);
3766 goto unlock;
3767 }
3768
3769 if (hdev_is_powered(hdev) &&
3770 !!cp->val != hci_dev_test_flag(hdev,
3771 HCI_WIDEBAND_SPEECH_ENABLED)) {
3772 err = mgmt_cmd_status(sk, hdev->id,
3773 MGMT_OP_SET_WIDEBAND_SPEECH,
3774 MGMT_STATUS_REJECTED);
3775 goto unlock;
3776 }
3777
3778 if (cp->val)
3779 changed = !hci_dev_test_and_set_flag(hdev,
3780 HCI_WIDEBAND_SPEECH_ENABLED);
3781 else
3782 changed = hci_dev_test_and_clear_flag(hdev,
3783 HCI_WIDEBAND_SPEECH_ENABLED);
3784
3785 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3786 if (err < 0)
3787 goto unlock;
3788
3789 if (changed)
3790 err = new_settings(hdev, sk);
3791
3792unlock:
3793 hci_dev_unlock(hdev);
3794 return err;
3795}
3796
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003797static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
3798 void *data, u16 data_len)
Marcel Holtmannbc292252020-04-03 21:44:05 +02003799{
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003800 char buf[20];
3801 struct mgmt_rp_read_controller_cap *rp = (void *)buf;
3802 u16 cap_len = 0;
Marcel Holtmannbc292252020-04-03 21:44:05 +02003803 u8 flags = 0;
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003804 u8 tx_power_range[2];
Marcel Holtmannbc292252020-04-03 21:44:05 +02003805
3806 bt_dev_dbg(hdev, "sock %p", sk);
3807
3808 memset(&buf, 0, sizeof(buf));
3809
3810 hci_dev_lock(hdev);
3811
3812 /* When the Read Simple Pairing Options command is supported, then
3813 * the remote public key validation is supported.
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003814 *
3815 * Alternatively, when Microsoft extensions are available, they can
3816 * indicate support for public key validation as well.
Marcel Holtmannbc292252020-04-03 21:44:05 +02003817 */
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003818 if ((hdev->commands[41] & 0x08) || msft_curve_validity(hdev))
Marcel Holtmannbc292252020-04-03 21:44:05 +02003819 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3820
3821 flags |= 0x02; /* Remote public key validation (LE) */
3822
3823 /* When the Read Encryption Key Size command is supported, then the
3824 * encryption key size is enforced.
3825 */
3826 if (hdev->commands[20] & 0x10)
3827 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3828
3829 flags |= 0x08; /* Encryption key size enforcement (LE) */
3830
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003831 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS,
3832 &flags, 1);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003833
3834 /* When the Read Simple Pairing Options command is supported, then
3835 * also max encryption key size information is provided.
3836 */
3837 if (hdev->commands[41] & 0x08)
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003838 cap_len = eir_append_le16(rp->cap, cap_len,
3839 MGMT_CAP_MAX_ENC_KEY_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02003840 hdev->max_enc_key_size);
3841
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003842 cap_len = eir_append_le16(rp->cap, cap_len,
3843 MGMT_CAP_SMP_MAX_ENC_KEY_SIZE,
3844 SMP_MAX_ENC_KEY_SIZE);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003845
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003846 /* Append the min/max LE tx power parameters if we were able to fetch
3847 * it from the controller
3848 */
3849 if (hdev->commands[38] & 0x80) {
3850 memcpy(&tx_power_range[0], &hdev->min_le_tx_power, 1);
3851 memcpy(&tx_power_range[1], &hdev->max_le_tx_power, 1);
3852 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR,
3853 tx_power_range, 2);
3854 }
3855
3856 rp->cap_len = cpu_to_le16(cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003857
3858 hci_dev_unlock(hdev);
3859
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003860 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0,
3861 rp, sizeof(*rp) + cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003862}
3863
Marcel Holtmanne625e502020-05-06 09:57:52 +02003864#ifdef CONFIG_BT_FEATURE_DEBUG
3865/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3866static const u8 debug_uuid[16] = {
3867 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3868 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3869};
3870#endif
3871
Joseph Hwangae7d9252021-08-15 20:17:16 +08003872/* 330859bc-7506-492d-9370-9a6f0614037f */
3873static const u8 quality_report_uuid[16] = {
3874 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
3875 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
3876};
3877
Kiran Kad933152021-09-07 15:42:47 +05303878/* a6695ace-ee7f-4fb9-881a-5fac66c629af */
3879static const u8 offload_codecs_uuid[16] = {
3880 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88,
3881 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6,
3882};
3883
Alain Michaud15d8ce02020-07-07 17:46:06 +02003884/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08003885static const u8 le_simultaneous_roles_uuid[16] = {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003886 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3887 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3888};
3889
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303890/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3891static const u8 rpa_resolution_uuid[16] = {
3892 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3893 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3894};
3895
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003896static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3897 void *data, u16 data_len)
3898{
Kiran Kad933152021-09-07 15:42:47 +05303899 char buf[102]; /* Enough space for 5 features: 2 + 20 * 5 */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003900 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3901 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003902 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003903
3904 bt_dev_dbg(hdev, "sock %p", sk);
3905
3906 memset(&buf, 0, sizeof(buf));
3907
Marcel Holtmanne625e502020-05-06 09:57:52 +02003908#ifdef CONFIG_BT_FEATURE_DEBUG
3909 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003910 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003911
3912 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3913 rp->features[idx].flags = cpu_to_le32(flags);
3914 idx++;
3915 }
3916#endif
3917
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08003918 if (hdev && hci_dev_le_state_simultaneous(hdev)) {
3919 if (hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
Alain Michaud15d8ce02020-07-07 17:46:06 +02003920 flags = BIT(0);
3921 else
3922 flags = 0;
3923
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08003924 memcpy(rp->features[idx].uuid, le_simultaneous_roles_uuid, 16);
Alain Michaud15d8ce02020-07-07 17:46:06 +02003925 rp->features[idx].flags = cpu_to_le32(flags);
3926 idx++;
3927 }
3928
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07003929 if (hdev && ll_privacy_capable(hdev)) {
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303930 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3931 flags = BIT(0) | BIT(1);
3932 else
3933 flags = BIT(1);
3934
3935 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3936 rp->features[idx].flags = cpu_to_le32(flags);
3937 idx++;
3938 }
3939
Joseph Hwang258f56d2021-11-02 15:19:29 +08003940 if (hdev && (aosp_has_quality_report(hdev) ||
3941 hdev->set_quality_report)) {
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003942 if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
Joseph Hwangae7d9252021-08-15 20:17:16 +08003943 flags = BIT(0);
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003944 else
Joseph Hwangae7d9252021-08-15 20:17:16 +08003945 flags = 0;
Marcel Holtmann823f3bc2021-09-28 12:10:14 +02003946
Joseph Hwangae7d9252021-08-15 20:17:16 +08003947 memcpy(rp->features[idx].uuid, quality_report_uuid, 16);
3948 rp->features[idx].flags = cpu_to_le32(flags);
3949 idx++;
3950 }
3951
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003952 if (hdev && hdev->get_data_path_id) {
3953 if (hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED))
Kiran Kad933152021-09-07 15:42:47 +05303954 flags = BIT(0);
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003955 else
Kiran Kad933152021-09-07 15:42:47 +05303956 flags = 0;
Marcel Holtmann7f7fd172021-09-28 12:10:15 +02003957
Kiran Kad933152021-09-07 15:42:47 +05303958 memcpy(rp->features[idx].uuid, offload_codecs_uuid, 16);
3959 rp->features[idx].flags = cpu_to_le32(flags);
3960 idx++;
3961 }
3962
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003963 rp->feature_count = cpu_to_le16(idx);
3964
3965 /* After reading the experimental features information, enable
3966 * the events to update client on any future change.
3967 */
3968 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3969
3970 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3971 MGMT_OP_READ_EXP_FEATURES_INFO,
3972 0, rp, sizeof(*rp) + (20 * idx));
3973}
3974
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303975static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3976 struct sock *skip)
3977{
3978 struct mgmt_ev_exp_feature_changed ev;
3979
3980 memset(&ev, 0, sizeof(ev));
3981 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3982 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3983
Luiz Augusto von Dentz6126ffa2021-12-03 14:07:22 -08003984 if (enabled && privacy_mode_capable(hdev))
3985 set_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
3986 else
3987 clear_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
3988
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303989 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3990 &ev, sizeof(ev),
3991 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3992
3993}
3994
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08003995static int exp_feature_changed(struct hci_dev *hdev, const u8 *uuid,
3996 bool enabled, struct sock *skip)
Marcel Holtmanne625e502020-05-06 09:57:52 +02003997{
3998 struct mgmt_ev_exp_feature_changed ev;
3999
4000 memset(&ev, 0, sizeof(ev));
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004001 memcpy(ev.uuid, uuid, 16);
Joseph Hwangae7d9252021-08-15 20:17:16 +08004002 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
4003
Tedd Ho-Jeong Anb15bfa42021-10-06 09:32:28 -07004004 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
Joseph Hwangae7d9252021-08-15 20:17:16 +08004005 &ev, sizeof(ev),
4006 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
4007}
4008
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004009#define EXP_FEAT(_uuid, _set_func) \
4010{ \
4011 .uuid = _uuid, \
4012 .set_func = _set_func, \
4013}
4014
4015/* The zero key uuid is special. Multiple exp features are set through it. */
4016static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
4017 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
4018{
4019 struct mgmt_rp_set_exp_feature rp;
4020
4021 memset(rp.uuid, 0, 16);
4022 rp.flags = cpu_to_le32(0);
4023
4024#ifdef CONFIG_BT_FEATURE_DEBUG
4025 if (!hdev) {
4026 bool changed = bt_dbg_get();
4027
4028 bt_dbg_set(false);
4029
4030 if (changed)
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004031 exp_feature_changed(NULL, ZERO_KEY, false, sk);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004032 }
4033#endif
4034
4035 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
Luiz Augusto von Dentz6f59f992021-12-01 11:49:49 -08004036 bool changed;
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004037
Luiz Augusto von Dentz6f59f992021-12-01 11:49:49 -08004038 changed = hci_dev_test_and_clear_flag(hdev,
4039 HCI_ENABLE_LL_PRIVACY);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004040 if (changed)
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004041 exp_feature_changed(hdev, rpa_resolution_uuid, false,
4042 sk);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004043 }
4044
4045 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4046
4047 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4048 MGMT_OP_SET_EXP_FEATURE, 0,
4049 &rp, sizeof(rp));
4050}
4051
4052#ifdef CONFIG_BT_FEATURE_DEBUG
4053static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
4054 struct mgmt_cp_set_exp_feature *cp, u16 data_len)
4055{
4056 struct mgmt_rp_set_exp_feature rp;
4057
4058 bool val, changed;
4059 int err;
4060
4061 /* Command requires to use the non-controller index */
4062 if (hdev)
4063 return mgmt_cmd_status(sk, hdev->id,
4064 MGMT_OP_SET_EXP_FEATURE,
4065 MGMT_STATUS_INVALID_INDEX);
4066
4067 /* Parameters are limited to a single octet */
4068 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4069 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4070 MGMT_OP_SET_EXP_FEATURE,
4071 MGMT_STATUS_INVALID_PARAMS);
4072
4073 /* Only boolean on/off is supported */
4074 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4075 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4076 MGMT_OP_SET_EXP_FEATURE,
4077 MGMT_STATUS_INVALID_PARAMS);
4078
4079 val = !!cp->param[0];
4080 changed = val ? !bt_dbg_get() : bt_dbg_get();
4081 bt_dbg_set(val);
4082
4083 memcpy(rp.uuid, debug_uuid, 16);
4084 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4085
4086 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4087
4088 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
4089 MGMT_OP_SET_EXP_FEATURE, 0,
4090 &rp, sizeof(rp));
4091
4092 if (changed)
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004093 exp_feature_changed(hdev, debug_uuid, val, sk);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004094
4095 return err;
4096}
4097#endif
4098
4099static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
4100 struct mgmt_cp_set_exp_feature *cp,
4101 u16 data_len)
4102{
4103 struct mgmt_rp_set_exp_feature rp;
4104 bool val, changed;
4105 int err;
4106 u32 flags;
4107
4108 /* Command requires to use the controller index */
4109 if (!hdev)
4110 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4111 MGMT_OP_SET_EXP_FEATURE,
4112 MGMT_STATUS_INVALID_INDEX);
4113
4114 /* Changes can only be made when controller is powered down */
4115 if (hdev_is_powered(hdev))
4116 return mgmt_cmd_status(sk, hdev->id,
4117 MGMT_OP_SET_EXP_FEATURE,
4118 MGMT_STATUS_REJECTED);
4119
4120 /* Parameters are limited to a single octet */
4121 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4122 return mgmt_cmd_status(sk, hdev->id,
4123 MGMT_OP_SET_EXP_FEATURE,
4124 MGMT_STATUS_INVALID_PARAMS);
4125
4126 /* Only boolean on/off is supported */
4127 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4128 return mgmt_cmd_status(sk, hdev->id,
4129 MGMT_OP_SET_EXP_FEATURE,
4130 MGMT_STATUS_INVALID_PARAMS);
4131
4132 val = !!cp->param[0];
4133
4134 if (val) {
Luiz Augusto von Dentz6f59f992021-12-01 11:49:49 -08004135 changed = !hci_dev_test_and_set_flag(hdev,
4136 HCI_ENABLE_LL_PRIVACY);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004137 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
4138
4139 /* Enable LL privacy + supported settings changed */
4140 flags = BIT(0) | BIT(1);
4141 } else {
Luiz Augusto von Dentz6f59f992021-12-01 11:49:49 -08004142 changed = hci_dev_test_and_clear_flag(hdev,
4143 HCI_ENABLE_LL_PRIVACY);
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004144
4145 /* Disable LL privacy + supported settings changed */
4146 flags = BIT(1);
4147 }
4148
4149 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4150 rp.flags = cpu_to_le32(flags);
4151
4152 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4153
4154 err = mgmt_cmd_complete(sk, hdev->id,
4155 MGMT_OP_SET_EXP_FEATURE, 0,
4156 &rp, sizeof(rp));
4157
4158 if (changed)
4159 exp_ll_privacy_feature_changed(val, hdev, sk);
4160
4161 return err;
4162}
4163
Joseph Hwangae7d9252021-08-15 20:17:16 +08004164static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
4165 struct mgmt_cp_set_exp_feature *cp,
4166 u16 data_len)
4167{
4168 struct mgmt_rp_set_exp_feature rp;
4169 bool val, changed;
4170 int err;
4171
4172 /* Command requires to use a valid controller index */
4173 if (!hdev)
4174 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4175 MGMT_OP_SET_EXP_FEATURE,
4176 MGMT_STATUS_INVALID_INDEX);
4177
4178 /* Parameters are limited to a single octet */
4179 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4180 return mgmt_cmd_status(sk, hdev->id,
4181 MGMT_OP_SET_EXP_FEATURE,
4182 MGMT_STATUS_INVALID_PARAMS);
4183
4184 /* Only boolean on/off is supported */
4185 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4186 return mgmt_cmd_status(sk, hdev->id,
4187 MGMT_OP_SET_EXP_FEATURE,
4188 MGMT_STATUS_INVALID_PARAMS);
4189
4190 hci_req_sync_lock(hdev);
4191
4192 val = !!cp->param[0];
4193 changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
4194
Joseph Hwang258f56d2021-11-02 15:19:29 +08004195 if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) {
Joseph Hwangae7d9252021-08-15 20:17:16 +08004196 err = mgmt_cmd_status(sk, hdev->id,
4197 MGMT_OP_SET_EXP_FEATURE,
4198 MGMT_STATUS_NOT_SUPPORTED);
4199 goto unlock_quality_report;
4200 }
4201
4202 if (changed) {
Joseph Hwang258f56d2021-11-02 15:19:29 +08004203 if (hdev->set_quality_report)
4204 err = hdev->set_quality_report(hdev, val);
4205 else
4206 err = aosp_set_quality_report(hdev, val);
4207
Joseph Hwangae7d9252021-08-15 20:17:16 +08004208 if (err) {
4209 err = mgmt_cmd_status(sk, hdev->id,
4210 MGMT_OP_SET_EXP_FEATURE,
4211 MGMT_STATUS_FAILED);
4212 goto unlock_quality_report;
4213 }
Joseph Hwang258f56d2021-11-02 15:19:29 +08004214
Joseph Hwangae7d9252021-08-15 20:17:16 +08004215 if (val)
4216 hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
4217 else
4218 hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
4219 }
4220
4221 bt_dev_dbg(hdev, "quality report enable %d changed %d", val, changed);
4222
4223 memcpy(rp.uuid, quality_report_uuid, 16);
4224 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4225 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
Joseph Hwang258f56d2021-11-02 15:19:29 +08004226
4227 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0,
Joseph Hwangae7d9252021-08-15 20:17:16 +08004228 &rp, sizeof(rp));
4229
4230 if (changed)
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004231 exp_feature_changed(hdev, quality_report_uuid, val, sk);
Joseph Hwangae7d9252021-08-15 20:17:16 +08004232
4233unlock_quality_report:
4234 hci_req_sync_unlock(hdev);
4235 return err;
4236}
4237
Kiran Kad933152021-09-07 15:42:47 +05304238static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
4239 struct mgmt_cp_set_exp_feature *cp,
4240 u16 data_len)
4241{
4242 bool val, changed;
4243 int err;
4244 struct mgmt_rp_set_exp_feature rp;
4245
4246 /* Command requires to use a valid controller index */
4247 if (!hdev)
4248 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4249 MGMT_OP_SET_EXP_FEATURE,
4250 MGMT_STATUS_INVALID_INDEX);
4251
4252 /* Parameters are limited to a single octet */
4253 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4254 return mgmt_cmd_status(sk, hdev->id,
4255 MGMT_OP_SET_EXP_FEATURE,
4256 MGMT_STATUS_INVALID_PARAMS);
4257
4258 /* Only boolean on/off is supported */
4259 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4260 return mgmt_cmd_status(sk, hdev->id,
4261 MGMT_OP_SET_EXP_FEATURE,
4262 MGMT_STATUS_INVALID_PARAMS);
4263
4264 val = !!cp->param[0];
4265 changed = (val != hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED));
4266
4267 if (!hdev->get_data_path_id) {
4268 return mgmt_cmd_status(sk, hdev->id,
4269 MGMT_OP_SET_EXP_FEATURE,
4270 MGMT_STATUS_NOT_SUPPORTED);
4271 }
4272
4273 if (changed) {
4274 if (val)
4275 hci_dev_set_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4276 else
4277 hci_dev_clear_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
4278 }
4279
4280 bt_dev_info(hdev, "offload codecs enable %d changed %d",
4281 val, changed);
4282
4283 memcpy(rp.uuid, offload_codecs_uuid, 16);
4284 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4285 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4286 err = mgmt_cmd_complete(sk, hdev->id,
4287 MGMT_OP_SET_EXP_FEATURE, 0,
4288 &rp, sizeof(rp));
4289
4290 if (changed)
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004291 exp_feature_changed(hdev, offload_codecs_uuid, val, sk);
4292
4293 return err;
4294}
4295
4296static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev,
4297 struct mgmt_cp_set_exp_feature *cp,
4298 u16 data_len)
4299{
4300 bool val, changed;
4301 int err;
4302 struct mgmt_rp_set_exp_feature rp;
4303
4304 /* Command requires to use a valid controller index */
4305 if (!hdev)
4306 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
4307 MGMT_OP_SET_EXP_FEATURE,
4308 MGMT_STATUS_INVALID_INDEX);
4309
4310 /* Parameters are limited to a single octet */
4311 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
4312 return mgmt_cmd_status(sk, hdev->id,
4313 MGMT_OP_SET_EXP_FEATURE,
4314 MGMT_STATUS_INVALID_PARAMS);
4315
4316 /* Only boolean on/off is supported */
4317 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4318 return mgmt_cmd_status(sk, hdev->id,
4319 MGMT_OP_SET_EXP_FEATURE,
4320 MGMT_STATUS_INVALID_PARAMS);
4321
4322 val = !!cp->param[0];
4323 changed = (val != hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES));
4324
4325 if (!hci_dev_le_state_simultaneous(hdev)) {
4326 return mgmt_cmd_status(sk, hdev->id,
4327 MGMT_OP_SET_EXP_FEATURE,
4328 MGMT_STATUS_NOT_SUPPORTED);
4329 }
4330
4331 if (changed) {
4332 if (val)
4333 hci_dev_set_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
4334 else
4335 hci_dev_clear_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
4336 }
4337
Colin Ian King5d1dd2e2021-12-23 09:47:17 +00004338 bt_dev_info(hdev, "LE simultaneous roles enable %d changed %d",
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004339 val, changed);
4340
4341 memcpy(rp.uuid, le_simultaneous_roles_uuid, 16);
4342 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
4343 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4344 err = mgmt_cmd_complete(sk, hdev->id,
4345 MGMT_OP_SET_EXP_FEATURE, 0,
4346 &rp, sizeof(rp));
4347
4348 if (changed)
4349 exp_feature_changed(hdev, le_simultaneous_roles_uuid, val, sk);
Kiran Kad933152021-09-07 15:42:47 +05304350
4351 return err;
4352}
4353
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004354static const struct mgmt_exp_feature {
4355 const u8 *uuid;
4356 int (*set_func)(struct sock *sk, struct hci_dev *hdev,
4357 struct mgmt_cp_set_exp_feature *cp, u16 data_len);
4358} exp_features[] = {
4359 EXP_FEAT(ZERO_KEY, set_zero_key_func),
4360#ifdef CONFIG_BT_FEATURE_DEBUG
4361 EXP_FEAT(debug_uuid, set_debug_func),
4362#endif
4363 EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
Joseph Hwangae7d9252021-08-15 20:17:16 +08004364 EXP_FEAT(quality_report_uuid, set_quality_report_func),
Kiran Kad933152021-09-07 15:42:47 +05304365 EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
Luiz Augusto von Dentz76d06852021-12-22 12:22:00 -08004366 EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func),
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004367
4368 /* end with a null feature */
4369 EXP_FEAT(NULL, NULL)
4370};
4371
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004372static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
4373 void *data, u16 data_len)
4374{
4375 struct mgmt_cp_set_exp_feature *cp = data;
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004376 size_t i = 0;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004377
4378 bt_dev_dbg(hdev, "sock %p", sk);
4379
Joseph Hwang93fb70b2021-08-15 20:17:15 +08004380 for (i = 0; exp_features[i].uuid; i++) {
4381 if (!memcmp(cp->uuid, exp_features[i].uuid, 16))
4382 return exp_features[i].set_func(sk, hdev, cp, data_len);
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05304383 }
4384
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004385 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4386 MGMT_OP_SET_EXP_FEATURE,
4387 MGMT_STATUS_NOT_SUPPORTED);
4388}
4389
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004390static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4391 u16 data_len)
4392{
4393 struct mgmt_cp_get_device_flags *cp = data;
4394 struct mgmt_rp_get_device_flags rp;
4395 struct bdaddr_list_with_flags *br_params;
4396 struct hci_conn_params *params;
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004397 u32 supported_flags;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004398 u32 current_flags = 0;
4399 u8 status = MGMT_STATUS_INVALID_PARAMS;
4400
4401 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4402 &cp->addr.bdaddr, cp->addr.type);
4403
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004404 hci_dev_lock(hdev);
4405
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004406 bitmap_to_arr32(&supported_flags, hdev->conn_flags,
4407 __HCI_CONN_NUM_FLAGS);
4408
Tedd Ho-Jeong An02ce2c22021-05-26 10:36:22 -07004409 memset(&rp, 0, sizeof(rp));
4410
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004411 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004412 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004413 &cp->addr.bdaddr,
4414 cp->addr.type);
4415 if (!br_params)
4416 goto done;
4417
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004418 bitmap_to_arr32(&current_flags, br_params->flags,
4419 __HCI_CONN_NUM_FLAGS);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004420 } else {
4421 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4422 le_addr_type(cp->addr.type));
4423
4424 if (!params)
4425 goto done;
4426
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004427 bitmap_to_arr32(&current_flags, params->flags,
4428 __HCI_CONN_NUM_FLAGS);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004429 }
4430
4431 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4432 rp.addr.type = cp->addr.type;
4433 rp.supported_flags = cpu_to_le32(supported_flags);
4434 rp.current_flags = cpu_to_le32(current_flags);
4435
4436 status = MGMT_STATUS_SUCCESS;
4437
4438done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004439 hci_dev_unlock(hdev);
4440
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004441 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4442 &rp, sizeof(rp));
4443}
4444
4445static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4446 bdaddr_t *bdaddr, u8 bdaddr_type,
4447 u32 supported_flags, u32 current_flags)
4448{
4449 struct mgmt_ev_device_flags_changed ev;
4450
4451 bacpy(&ev.addr.bdaddr, bdaddr);
4452 ev.addr.type = bdaddr_type;
4453 ev.supported_flags = cpu_to_le32(supported_flags);
4454 ev.current_flags = cpu_to_le32(current_flags);
4455
4456 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4457}
4458
4459static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4460 u16 len)
4461{
4462 struct mgmt_cp_set_device_flags *cp = data;
4463 struct bdaddr_list_with_flags *br_params;
4464 struct hci_conn_params *params;
4465 u8 status = MGMT_STATUS_INVALID_PARAMS;
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004466 u32 supported_flags;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004467 u32 current_flags = __le32_to_cpu(cp->current_flags);
4468
4469 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4470 &cp->addr.bdaddr, cp->addr.type,
4471 __le32_to_cpu(current_flags));
4472
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004473 bitmap_to_arr32(&supported_flags, hdev->conn_flags,
4474 __HCI_CONN_NUM_FLAGS);
4475
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004476 if ((supported_flags | current_flags) != supported_flags) {
4477 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4478 current_flags, supported_flags);
4479 goto done;
4480 }
4481
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004482 hci_dev_lock(hdev);
4483
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004484 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08004485 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004486 &cp->addr.bdaddr,
4487 cp->addr.type);
4488
4489 if (br_params) {
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004490 bitmap_from_u64(br_params->flags, current_flags);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004491 status = MGMT_STATUS_SUCCESS;
4492 } else {
4493 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4494 &cp->addr.bdaddr, cp->addr.type);
4495 }
4496 } else {
4497 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4498 le_addr_type(cp->addr.type));
4499 if (params) {
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08004500 bitmap_from_u64(params->flags, current_flags);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004501 status = MGMT_STATUS_SUCCESS;
Luiz Augusto von Dentz6126ffa2021-12-03 14:07:22 -08004502
4503 /* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
4504 * has been set.
4505 */
4506 if (test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY,
4507 params->flags))
4508 hci_update_passive_scan(hdev);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004509 } else {
4510 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4511 &cp->addr.bdaddr,
4512 le_addr_type(cp->addr.type));
4513 }
4514 }
4515
4516done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004517 hci_dev_unlock(hdev);
4518
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004519 if (status == MGMT_STATUS_SUCCESS)
4520 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4521 supported_flags, current_flags);
4522
4523 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4524 &cp->addr, sizeof(cp->addr));
4525}
4526
Miao-chen Choub52729f2020-06-17 16:39:16 +02004527static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4528 u16 handle)
4529{
4530 struct mgmt_ev_adv_monitor_added ev;
4531
4532 ev.monitor_handle = cpu_to_le16(handle);
4533
4534 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4535}
4536
Archie Pusaka66bd0952021-01-22 16:36:13 +08004537void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004538{
Archie Pusaka66bd0952021-01-22 16:36:13 +08004539 struct mgmt_ev_adv_monitor_removed ev;
4540 struct mgmt_pending_cmd *cmd;
4541 struct sock *sk_skip = NULL;
4542 struct mgmt_cp_remove_adv_monitor *cp;
4543
4544 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4545 if (cmd) {
4546 cp = cmd->param;
4547
4548 if (cp->monitor_handle)
4549 sk_skip = cmd->sk;
4550 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004551
4552 ev.monitor_handle = cpu_to_le16(handle);
4553
Archie Pusaka66bd0952021-01-22 16:36:13 +08004554 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004555}
4556
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004557static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4558 void *data, u16 len)
4559{
4560 struct adv_monitor *monitor = NULL;
4561 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004562 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004563 size_t rp_size = 0;
4564 __u32 supported = 0;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004565 __u32 enabled = 0;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004566 __u16 num_handles = 0;
4567 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4568
4569 BT_DBG("request for %s", hdev->name);
4570
4571 hci_dev_lock(hdev);
4572
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004573 if (msft_monitor_supported(hdev))
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004574 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4575
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004576 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004577 handles[num_handles++] = monitor->handle;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004578
4579 hci_dev_unlock(hdev);
4580
4581 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4582 rp = kmalloc(rp_size, GFP_KERNEL);
4583 if (!rp)
4584 return -ENOMEM;
4585
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004586 /* All supported features are currently enabled */
4587 enabled = supported;
4588
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004589 rp->supported_features = cpu_to_le32(supported);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004590 rp->enabled_features = cpu_to_le32(enabled);
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004591 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4592 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4593 rp->num_handles = cpu_to_le16(num_handles);
4594 if (num_handles)
4595 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4596
Peilin Yecafd4722020-09-09 03:25:51 -04004597 err = mgmt_cmd_complete(sk, hdev->id,
4598 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4599 MGMT_STATUS_SUCCESS, rp, rp_size);
4600
4601 kfree(rp);
4602
4603 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004604}
4605
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004606int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
Miao-chen Choub1395532020-06-17 16:39:14 +02004607{
Miao-chen Choub1395532020-06-17 16:39:14 +02004608 struct mgmt_rp_add_adv_patterns_monitor rp;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004609 struct mgmt_pending_cmd *cmd;
4610 struct adv_monitor *monitor;
4611 int err = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004612
4613 hci_dev_lock(hdev);
4614
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004615 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4616 if (!cmd) {
4617 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4618 if (!cmd)
4619 goto done;
4620 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004621
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004622 monitor = cmd->user_data;
4623 rp.monitor_handle = cpu_to_le16(monitor->handle);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004624
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004625 if (!status) {
4626 mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4627 hdev->adv_monitors_cnt++;
4628 if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4629 monitor->state = ADV_MONITOR_STATE_REGISTERED;
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004630 hci_update_passive_scan(hdev);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004631 }
4632
4633 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4634 mgmt_status(status), &rp, sizeof(rp));
4635 mgmt_pending_remove(cmd);
4636
4637done:
4638 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004639 bt_dev_dbg(hdev, "add monitor %d complete, status %u",
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004640 rp.monitor_handle, status);
4641
4642 return err;
4643}
4644
4645static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4646 struct adv_monitor *m, u8 status,
4647 void *data, u16 len, u16 op)
4648{
4649 struct mgmt_rp_add_adv_patterns_monitor rp;
4650 struct mgmt_pending_cmd *cmd;
4651 int err;
4652 bool pending;
4653
4654 hci_dev_lock(hdev);
4655
4656 if (status)
4657 goto unlock;
4658
4659 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4660 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4661 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4662 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4663 status = MGMT_STATUS_BUSY;
Miao-chen Choub1395532020-06-17 16:39:14 +02004664 goto unlock;
4665 }
4666
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004667 cmd = mgmt_pending_add(sk, op, hdev, data, len);
4668 if (!cmd) {
4669 status = MGMT_STATUS_NO_RESOURCES;
4670 goto unlock;
4671 }
4672
Howard Chungb1810fe2021-02-03 15:09:29 +08004673 cmd->user_data = m;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004674 pending = hci_add_adv_monitor(hdev, m, &err);
4675 if (err) {
4676 if (err == -ENOSPC || err == -ENOMEM)
4677 status = MGMT_STATUS_NO_RESOURCES;
4678 else if (err == -EINVAL)
4679 status = MGMT_STATUS_INVALID_PARAMS;
4680 else
4681 status = MGMT_STATUS_FAILED;
4682
4683 mgmt_pending_remove(cmd);
4684 goto unlock;
4685 }
4686
4687 if (!pending) {
4688 mgmt_pending_remove(cmd);
4689 rp.monitor_handle = cpu_to_le16(m->handle);
Miao-chen Choub52729f2020-06-17 16:39:16 +02004690 mgmt_adv_monitor_added(sk, hdev, m->handle);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004691 m->state = ADV_MONITOR_STATE_REGISTERED;
4692 hdev->adv_monitors_cnt++;
4693
4694 hci_dev_unlock(hdev);
4695 return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4696 &rp, sizeof(rp));
4697 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004698
Miao-chen Choub1395532020-06-17 16:39:14 +02004699 hci_dev_unlock(hdev);
4700
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004701 return 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004702
4703unlock:
Archie Pusaka66bd0952021-01-22 16:36:13 +08004704 hci_free_adv_monitor(hdev, m);
Miao-chen Choub1395532020-06-17 16:39:14 +02004705 hci_dev_unlock(hdev);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004706 return mgmt_cmd_status(sk, hdev->id, op, status);
4707}
4708
4709static void parse_adv_monitor_rssi(struct adv_monitor *m,
4710 struct mgmt_adv_rssi_thresholds *rssi)
4711{
4712 if (rssi) {
4713 m->rssi.low_threshold = rssi->low_threshold;
4714 m->rssi.low_threshold_timeout =
4715 __le16_to_cpu(rssi->low_threshold_timeout);
4716 m->rssi.high_threshold = rssi->high_threshold;
4717 m->rssi.high_threshold_timeout =
4718 __le16_to_cpu(rssi->high_threshold_timeout);
4719 m->rssi.sampling_period = rssi->sampling_period;
4720 } else {
4721 /* Default values. These numbers are the least constricting
4722 * parameters for MSFT API to work, so it behaves as if there
4723 * are no rssi parameter to consider. May need to be changed
4724 * if other API are to be supported.
4725 */
4726 m->rssi.low_threshold = -127;
4727 m->rssi.low_threshold_timeout = 60;
4728 m->rssi.high_threshold = -127;
4729 m->rssi.high_threshold_timeout = 0;
4730 m->rssi.sampling_period = 0;
4731 }
4732}
4733
4734static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
4735 struct mgmt_adv_pattern *patterns)
4736{
4737 u8 offset = 0, length = 0;
4738 struct adv_pattern *p = NULL;
Archie Pusakab4a221e2021-01-22 16:36:11 +08004739 int i;
4740
4741 for (i = 0; i < pattern_count; i++) {
Archie Pusakab4a221e2021-01-22 16:36:11 +08004742 offset = patterns[i].offset;
4743 length = patterns[i].length;
4744 if (offset >= HCI_MAX_AD_LENGTH ||
4745 length > HCI_MAX_AD_LENGTH ||
4746 (offset + length) > HCI_MAX_AD_LENGTH)
4747 return MGMT_STATUS_INVALID_PARAMS;
4748
4749 p = kmalloc(sizeof(*p), GFP_KERNEL);
4750 if (!p)
4751 return MGMT_STATUS_NO_RESOURCES;
4752
4753 p->ad_type = patterns[i].ad_type;
4754 p->offset = patterns[i].offset;
4755 p->length = patterns[i].length;
4756 memcpy(p->value, patterns[i].value, p->length);
4757
4758 INIT_LIST_HEAD(&p->list);
4759 list_add(&p->list, &m->patterns);
4760 }
4761
Archie Pusakab4a221e2021-01-22 16:36:11 +08004762 return MGMT_STATUS_SUCCESS;
4763}
4764
4765static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4766 void *data, u16 len)
4767{
4768 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4769 struct adv_monitor *m = NULL;
4770 u8 status = MGMT_STATUS_SUCCESS;
4771 size_t expected_size = sizeof(*cp);
4772
4773 BT_DBG("request for %s", hdev->name);
4774
4775 if (len <= sizeof(*cp)) {
4776 status = MGMT_STATUS_INVALID_PARAMS;
4777 goto done;
4778 }
4779
4780 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4781 if (len != expected_size) {
4782 status = MGMT_STATUS_INVALID_PARAMS;
4783 goto done;
4784 }
4785
4786 m = kzalloc(sizeof(*m), GFP_KERNEL);
4787 if (!m) {
4788 status = MGMT_STATUS_NO_RESOURCES;
4789 goto done;
4790 }
4791
4792 INIT_LIST_HEAD(&m->patterns);
4793
4794 parse_adv_monitor_rssi(m, NULL);
4795 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4796
4797done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004798 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004799 MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
4800}
4801
4802static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
4803 void *data, u16 len)
4804{
4805 struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = data;
4806 struct adv_monitor *m = NULL;
4807 u8 status = MGMT_STATUS_SUCCESS;
4808 size_t expected_size = sizeof(*cp);
4809
4810 BT_DBG("request for %s", hdev->name);
4811
4812 if (len <= sizeof(*cp)) {
4813 status = MGMT_STATUS_INVALID_PARAMS;
4814 goto done;
4815 }
4816
4817 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4818 if (len != expected_size) {
4819 status = MGMT_STATUS_INVALID_PARAMS;
4820 goto done;
4821 }
4822
4823 m = kzalloc(sizeof(*m), GFP_KERNEL);
4824 if (!m) {
4825 status = MGMT_STATUS_NO_RESOURCES;
4826 goto done;
4827 }
4828
4829 INIT_LIST_HEAD(&m->patterns);
4830
4831 parse_adv_monitor_rssi(m, &cp->rssi);
4832 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4833
4834done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004835 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004836 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
Miao-chen Choub1395532020-06-17 16:39:14 +02004837}
4838
Archie Pusaka66bd0952021-01-22 16:36:13 +08004839int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4840{
4841 struct mgmt_rp_remove_adv_monitor rp;
4842 struct mgmt_cp_remove_adv_monitor *cp;
4843 struct mgmt_pending_cmd *cmd;
4844 int err = 0;
4845
4846 hci_dev_lock(hdev);
4847
4848 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4849 if (!cmd)
4850 goto done;
4851
4852 cp = cmd->param;
4853 rp.monitor_handle = cp->monitor_handle;
4854
4855 if (!status)
Luiz Augusto von Dentz5bee2fd2021-10-27 16:58:43 -07004856 hci_update_passive_scan(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004857
4858 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4859 mgmt_status(status), &rp, sizeof(rp));
4860 mgmt_pending_remove(cmd);
4861
4862done:
4863 hci_dev_unlock(hdev);
Kai Ye85d672842021-06-03 15:41:02 +08004864 bt_dev_dbg(hdev, "remove monitor %d complete, status %u",
Archie Pusaka66bd0952021-01-22 16:36:13 +08004865 rp.monitor_handle, status);
4866
4867 return err;
4868}
4869
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004870static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4871 void *data, u16 len)
4872{
4873 struct mgmt_cp_remove_adv_monitor *cp = data;
4874 struct mgmt_rp_remove_adv_monitor rp;
Archie Pusaka66bd0952021-01-22 16:36:13 +08004875 struct mgmt_pending_cmd *cmd;
4876 u16 handle = __le16_to_cpu(cp->monitor_handle);
4877 int err, status;
4878 bool pending;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004879
4880 BT_DBG("request for %s", hdev->name);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004881 rp.monitor_handle = cp->monitor_handle;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004882
4883 hci_dev_lock(hdev);
4884
Archie Pusaka66bd0952021-01-22 16:36:13 +08004885 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4886 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4887 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4888 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4889 status = MGMT_STATUS_BUSY;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004890 goto unlock;
4891 }
4892
Archie Pusaka66bd0952021-01-22 16:36:13 +08004893 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4894 if (!cmd) {
4895 status = MGMT_STATUS_NO_RESOURCES;
4896 goto unlock;
4897 }
4898
4899 if (handle)
4900 pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4901 else
4902 pending = hci_remove_all_adv_monitor(hdev, &err);
4903
4904 if (err) {
4905 mgmt_pending_remove(cmd);
4906
4907 if (err == -ENOENT)
4908 status = MGMT_STATUS_INVALID_INDEX;
4909 else
4910 status = MGMT_STATUS_FAILED;
4911
4912 goto unlock;
4913 }
4914
4915 /* monitor can be removed without forwarding request to controller */
4916 if (!pending) {
4917 mgmt_pending_remove(cmd);
4918 hci_dev_unlock(hdev);
4919
4920 return mgmt_cmd_complete(sk, hdev->id,
4921 MGMT_OP_REMOVE_ADV_MONITOR,
4922 MGMT_STATUS_SUCCESS,
4923 &rp, sizeof(rp));
4924 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004925
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004926 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004927 return 0;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004928
4929unlock:
4930 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004931 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4932 status);
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004933}
4934
Brian Gixf8922442021-10-27 16:58:52 -07004935static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004936{
4937 struct mgmt_rp_read_local_oob_data mgmt_rp;
4938 size_t rp_size = sizeof(mgmt_rp);
Brian Gixf8922442021-10-27 16:58:52 -07004939 struct mgmt_pending_cmd *cmd = data;
4940 struct sk_buff *skb = cmd->skb;
4941 u8 status = mgmt_status(err);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004942
Brian Gixf8922442021-10-27 16:58:52 -07004943 if (!status) {
4944 if (!skb)
4945 status = MGMT_STATUS_FAILED;
4946 else if (IS_ERR(skb))
4947 status = mgmt_status(PTR_ERR(skb));
4948 else
4949 status = mgmt_status(skb->data[0]);
4950 }
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004951
Brian Gixf8922442021-10-27 16:58:52 -07004952 bt_dev_dbg(hdev, "status %d", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004953
Brian Gixf8922442021-10-27 16:58:52 -07004954 if (status) {
4955 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004956 goto remove;
4957 }
4958
4959 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4960
Brian Gixf8922442021-10-27 16:58:52 -07004961 if (!bredr_sc_enabled(hdev)) {
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004962 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4963
4964 if (skb->len < sizeof(*rp)) {
4965 mgmt_cmd_status(cmd->sk, hdev->id,
4966 MGMT_OP_READ_LOCAL_OOB_DATA,
4967 MGMT_STATUS_FAILED);
4968 goto remove;
4969 }
4970
4971 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4972 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4973
4974 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4975 } else {
4976 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4977
4978 if (skb->len < sizeof(*rp)) {
4979 mgmt_cmd_status(cmd->sk, hdev->id,
4980 MGMT_OP_READ_LOCAL_OOB_DATA,
4981 MGMT_STATUS_FAILED);
4982 goto remove;
4983 }
4984
4985 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4986 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4987
4988 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4989 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4990 }
4991
4992 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4993 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4994
4995remove:
Brian Gixf8922442021-10-27 16:58:52 -07004996 if (skb && !IS_ERR(skb))
4997 kfree_skb(skb);
4998
4999 mgmt_pending_free(cmd);
5000}
5001
5002static int read_local_oob_data_sync(struct hci_dev *hdev, void *data)
5003{
5004 struct mgmt_pending_cmd *cmd = data;
5005
5006 if (bredr_sc_enabled(hdev))
5007 cmd->skb = hci_read_local_oob_data_sync(hdev, true, cmd->sk);
5008 else
5009 cmd->skb = hci_read_local_oob_data_sync(hdev, false, cmd->sk);
5010
5011 if (IS_ERR(cmd->skb))
5012 return PTR_ERR(cmd->skb);
5013 else
5014 return 0;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03005015}
5016
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02005017static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005018 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01005019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005020 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005021 int err;
5022
Marcel Holtmann181d6952020-05-06 09:57:47 +02005023 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01005024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005025 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005026
Johan Hedberg4b34ee782012-02-21 14:13:02 +02005027 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005028 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5029 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01005030 goto unlock;
5031 }
5032
Andre Guedes9a1a1992012-07-24 15:03:48 -03005033 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005034 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5035 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01005036 goto unlock;
5037 }
5038
Johan Hedberg333ae952015-03-17 13:48:47 +02005039 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005040 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5041 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01005042 goto unlock;
5043 }
5044
Brian Gixf8922442021-10-27 16:58:52 -07005045 cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
5046 if (!cmd)
Szymon Jancc35938b2011-03-22 13:12:21 +01005047 err = -ENOMEM;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03005048 else
Brian Gixf8922442021-10-27 16:58:52 -07005049 err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
5050 read_local_oob_data_complete);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03005051
Brian Gixf8922442021-10-27 16:58:52 -07005052 if (err < 0) {
5053 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5054 MGMT_STATUS_FAILED);
5055
5056 if (cmd)
5057 mgmt_pending_free(cmd);
5058 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005059
5060unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005061 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005062 return err;
5063}
5064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005065static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005066 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01005067{
Johan Hedberg5d57e792015-01-23 10:10:38 +02005068 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01005069 int err;
5070
Marcel Holtmann181d6952020-05-06 09:57:47 +02005071 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01005072
Johan Hedberg5d57e792015-01-23 10:10:38 +02005073 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005074 return mgmt_cmd_complete(sk, hdev->id,
5075 MGMT_OP_ADD_REMOTE_OOB_DATA,
5076 MGMT_STATUS_INVALID_PARAMS,
5077 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02005078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005079 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005080
Marcel Holtmannec109112014-01-10 02:07:30 -08005081 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
5082 struct mgmt_cp_add_remote_oob_data *cp = data;
5083 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005084
Johan Hedbergc19a4952014-11-17 20:52:19 +02005085 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005086 err = mgmt_cmd_complete(sk, hdev->id,
5087 MGMT_OP_ADD_REMOTE_OOB_DATA,
5088 MGMT_STATUS_INVALID_PARAMS,
5089 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02005090 goto unlock;
5091 }
5092
Marcel Holtmannec109112014-01-10 02:07:30 -08005093 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01005094 cp->addr.type, cp->hash,
5095 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08005096 if (err < 0)
5097 status = MGMT_STATUS_FAILED;
5098 else
5099 status = MGMT_STATUS_SUCCESS;
5100
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005101 err = mgmt_cmd_complete(sk, hdev->id,
5102 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
5103 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08005104 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
5105 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005106 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08005107 u8 status;
5108
Johan Hedberg86df9202014-10-26 20:52:27 +01005109 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02005110 /* Enforce zero-valued 192-bit parameters as
5111 * long as legacy SMP OOB isn't implemented.
5112 */
5113 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
5114 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005115 err = mgmt_cmd_complete(sk, hdev->id,
5116 MGMT_OP_ADD_REMOTE_OOB_DATA,
5117 MGMT_STATUS_INVALID_PARAMS,
5118 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02005119 goto unlock;
5120 }
5121
Johan Hedberg86df9202014-10-26 20:52:27 +01005122 rand192 = NULL;
5123 hash192 = NULL;
5124 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005125 /* In case one of the P-192 values is set to zero,
5126 * then just disable OOB data for P-192.
5127 */
5128 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
5129 !memcmp(cp->hash192, ZERO_KEY, 16)) {
5130 rand192 = NULL;
5131 hash192 = NULL;
5132 } else {
5133 rand192 = cp->rand192;
5134 hash192 = cp->hash192;
5135 }
5136 }
5137
5138 /* In case one of the P-256 values is set to zero, then just
5139 * disable OOB data for P-256.
5140 */
5141 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
5142 !memcmp(cp->hash256, ZERO_KEY, 16)) {
5143 rand256 = NULL;
5144 hash256 = NULL;
5145 } else {
5146 rand256 = cp->rand256;
5147 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01005148 }
5149
Johan Hedberg81328d5c2014-10-26 20:33:47 +01005150 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01005151 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08005152 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08005153 if (err < 0)
5154 status = MGMT_STATUS_FAILED;
5155 else
5156 status = MGMT_STATUS_SUCCESS;
5157
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005158 err = mgmt_cmd_complete(sk, hdev->id,
5159 MGMT_OP_ADD_REMOTE_OOB_DATA,
5160 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08005161 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005162 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
5163 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005164 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
5165 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08005166 }
Szymon Janc2763eda2011-03-22 13:12:22 +01005167
Johan Hedbergc19a4952014-11-17 20:52:19 +02005168unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005169 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005170 return err;
5171}
5172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005173static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005174 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01005175{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005176 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005177 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01005178 int err;
5179
Marcel Holtmann181d6952020-05-06 09:57:47 +02005180 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01005181
Johan Hedbergc19a4952014-11-17 20:52:19 +02005182 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005183 return mgmt_cmd_complete(sk, hdev->id,
5184 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5185 MGMT_STATUS_INVALID_PARAMS,
5186 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02005187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005188 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005189
Johan Hedbergeedbd582014-11-15 09:34:23 +02005190 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5191 hci_remote_oob_data_clear(hdev);
5192 status = MGMT_STATUS_SUCCESS;
5193 goto done;
5194 }
5195
Johan Hedberg6928a922014-10-26 20:46:09 +01005196 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01005197 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005198 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01005199 else
Szymon Janca6785be2012-12-13 15:11:21 +01005200 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02005201
Johan Hedbergeedbd582014-11-15 09:34:23 +02005202done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005203 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
5204 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01005205
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005206 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01005207 return err;
5208}
5209
Johan Hedberge68f0722015-11-11 08:30:30 +02005210void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03005211{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005212 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01005213
Kai Ye85d672842021-06-03 15:41:02 +08005214 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes7c307722013-04-30 15:29:28 -03005215
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005216 hci_dev_lock(hdev);
5217
Johan Hedberg333ae952015-03-17 13:48:47 +02005218 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005219 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02005220 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005221
Johan Hedberg78b781c2016-01-05 13:19:32 +02005222 if (!cmd)
5223 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
5224
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005225 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005226 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005227 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03005228 }
5229
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005230 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03005231}
5232
Johan Hedberg591752a2015-11-11 08:11:24 +02005233static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
5234 uint8_t *mgmt_status)
5235{
5236 switch (type) {
5237 case DISCOV_TYPE_LE:
5238 *mgmt_status = mgmt_le_support(hdev);
5239 if (*mgmt_status)
5240 return false;
5241 break;
5242 case DISCOV_TYPE_INTERLEAVED:
5243 *mgmt_status = mgmt_le_support(hdev);
5244 if (*mgmt_status)
5245 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05005246 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02005247 case DISCOV_TYPE_BREDR:
5248 *mgmt_status = mgmt_bredr_support(hdev);
5249 if (*mgmt_status)
5250 return false;
5251 break;
5252 default:
5253 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
5254 return false;
5255 }
5256
5257 return true;
5258}
5259
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005260static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
5261{
5262 struct mgmt_pending_cmd *cmd = data;
5263
5264 bt_dev_dbg(hdev, "err %d", err);
5265
5266 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5267 cmd->param, 1);
5268 mgmt_pending_free(cmd);
5269
Luiz Augusto von Dentz182ee452021-10-27 16:59:00 -07005270 hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005271 DISCOVERY_FINDING);
5272}
5273
5274static int start_discovery_sync(struct hci_dev *hdev, void *data)
5275{
5276 return hci_start_discovery_sync(hdev);
5277}
5278
Johan Hedberg78b781c2016-01-05 13:19:32 +02005279static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
5280 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005281{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005282 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005283 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01005284 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04005285 int err;
5286
Marcel Holtmann181d6952020-05-06 09:57:47 +02005287 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005289 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005290
Johan Hedberg4b34ee782012-02-21 14:13:02 +02005291 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005292 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005293 MGMT_STATUS_NOT_POWERED,
5294 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02005295 goto failed;
5296 }
5297
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005298 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005299 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005300 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5301 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03005302 goto failed;
5303 }
5304
Johan Hedberg591752a2015-11-11 08:11:24 +02005305 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02005306 err = mgmt_cmd_complete(sk, hdev->id, op, status,
5307 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02005308 goto failed;
5309 }
5310
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005311 /* Can't start discovery when it is paused */
5312 if (hdev->discovery_paused) {
5313 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
5314 &cp->type, sizeof(cp->type));
5315 goto failed;
5316 }
5317
Marcel Holtmann22078802014-12-05 11:45:22 +01005318 /* Clear the discovery filter first to free any previously
5319 * allocated memory for the UUID list.
5320 */
5321 hci_discovery_filter_clear(hdev);
5322
Andre Guedes4aab14e2012-02-17 20:39:36 -03005323 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01005324 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02005325 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
5326 hdev->discovery.limited = true;
5327 else
5328 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03005329
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005330 cmd = mgmt_pending_new(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02005331 if (!cmd) {
5332 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02005333 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03005334 }
Andre Guedes3fd24152012-02-03 17:48:01 -03005335
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005336 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5337 start_discovery_complete);
5338 if (err < 0) {
5339 mgmt_pending_free(cmd);
5340 goto failed;
5341 }
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01005342
5343 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005344
5345failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005346 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005347 return err;
5348}
5349
Johan Hedberg78b781c2016-01-05 13:19:32 +02005350static int start_discovery(struct sock *sk, struct hci_dev *hdev,
5351 void *data, u16 len)
5352{
5353 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
5354 data, len);
5355}
5356
5357static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
5358 void *data, u16 len)
5359{
5360 return start_discovery_internal(sk, hdev,
5361 MGMT_OP_START_LIMITED_DISCOVERY,
5362 data, len);
5363}
5364
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005365static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
5366 void *data, u16 len)
5367{
5368 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005369 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005370 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
5371 u16 uuid_count, expected_len;
5372 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03005373 int err;
5374
Marcel Holtmann181d6952020-05-06 09:57:47 +02005375 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005376
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005377 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005378
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005379 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005380 err = mgmt_cmd_complete(sk, hdev->id,
5381 MGMT_OP_START_SERVICE_DISCOVERY,
5382 MGMT_STATUS_NOT_POWERED,
5383 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005384 goto failed;
5385 }
5386
5387 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005388 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005389 err = mgmt_cmd_complete(sk, hdev->id,
5390 MGMT_OP_START_SERVICE_DISCOVERY,
5391 MGMT_STATUS_BUSY, &cp->type,
5392 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005393 goto failed;
5394 }
5395
Abhishek Pandit-Subedi36211f72020-12-17 15:04:08 -08005396 if (hdev->discovery_paused) {
5397 err = mgmt_cmd_complete(sk, hdev->id,
5398 MGMT_OP_START_SERVICE_DISCOVERY,
5399 MGMT_STATUS_BUSY, &cp->type,
5400 sizeof(cp->type));
5401 goto failed;
5402 }
5403
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005404 uuid_count = __le16_to_cpu(cp->uuid_count);
5405 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005406 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
5407 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005408 err = mgmt_cmd_complete(sk, hdev->id,
5409 MGMT_OP_START_SERVICE_DISCOVERY,
5410 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5411 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005412 goto failed;
5413 }
5414
5415 expected_len = sizeof(*cp) + uuid_count * 16;
5416 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005417 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
5418 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005419 err = mgmt_cmd_complete(sk, hdev->id,
5420 MGMT_OP_START_SERVICE_DISCOVERY,
5421 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5422 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005423 goto failed;
5424 }
5425
Johan Hedberg591752a2015-11-11 08:11:24 +02005426 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
5427 err = mgmt_cmd_complete(sk, hdev->id,
5428 MGMT_OP_START_SERVICE_DISCOVERY,
5429 status, &cp->type, sizeof(cp->type));
5430 goto failed;
5431 }
5432
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005433 cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02005434 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005435 if (!cmd) {
5436 err = -ENOMEM;
5437 goto failed;
5438 }
5439
Marcel Holtmann22078802014-12-05 11:45:22 +01005440 /* Clear the discovery filter first to free any previously
5441 * allocated memory for the UUID list.
5442 */
5443 hci_discovery_filter_clear(hdev);
5444
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08005445 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005446 hdev->discovery.type = cp->type;
5447 hdev->discovery.rssi = cp->rssi;
5448 hdev->discovery.uuid_count = uuid_count;
5449
5450 if (uuid_count > 0) {
5451 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
5452 GFP_KERNEL);
5453 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005454 err = mgmt_cmd_complete(sk, hdev->id,
5455 MGMT_OP_START_SERVICE_DISCOVERY,
5456 MGMT_STATUS_FAILED,
5457 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005458 mgmt_pending_remove(cmd);
5459 goto failed;
5460 }
5461 }
5462
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005463 err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
5464 start_discovery_complete);
5465 if (err < 0) {
5466 mgmt_pending_free(cmd);
5467 goto failed;
5468 }
5469
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005470 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
5471
5472failed:
5473 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005474 return err;
5475}
5476
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005477void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03005478{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005479 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005480
Kai Ye85d672842021-06-03 15:41:02 +08005481 bt_dev_dbg(hdev, "status %u", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005482
5483 hci_dev_lock(hdev);
5484
Johan Hedberg333ae952015-03-17 13:48:47 +02005485 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005486 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005487 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005488 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005489 }
5490
Andre Guedes0e05bba2013-04-30 15:29:33 -03005491 hci_dev_unlock(hdev);
5492}
5493
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005494static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
5495{
5496 struct mgmt_pending_cmd *cmd = data;
5497
5498 bt_dev_dbg(hdev, "err %d", err);
5499
5500 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
5501 cmd->param, 1);
5502 mgmt_pending_free(cmd);
5503
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005504 if (!err)
5505 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
5506}
5507
5508static int stop_discovery_sync(struct hci_dev *hdev, void *data)
5509{
5510 return hci_stop_discovery_sync(hdev);
5511}
5512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005513static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005514 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005515{
Johan Hedbergd9306502012-02-20 23:25:18 +02005516 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005517 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04005518 int err;
5519
Marcel Holtmann181d6952020-05-06 09:57:47 +02005520 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005522 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005523
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005524 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005525 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5526 MGMT_STATUS_REJECTED, &mgmt_cp->type,
5527 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02005528 goto unlock;
5529 }
5530
5531 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005532 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5533 MGMT_STATUS_INVALID_PARAMS,
5534 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005535 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02005536 }
5537
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005538 cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04005539 if (!cmd) {
5540 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005541 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04005542 }
5543
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005544 err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd,
5545 stop_discovery_complete);
5546 if (err < 0) {
5547 mgmt_pending_free(cmd);
5548 goto unlock;
5549 }
Johan Hedberg2922a942014-12-05 13:36:06 +02005550
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005551 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04005552
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005553unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005554 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005555 return err;
5556}
5557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005558static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005559 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02005560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005561 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005562 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005563 int err;
5564
Marcel Holtmann181d6952020-05-06 09:57:47 +02005565 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005566
Johan Hedberg561aafb2012-01-04 13:31:59 +02005567 hci_dev_lock(hdev);
5568
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005569 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005570 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5571 MGMT_STATUS_FAILED, &cp->addr,
5572 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005573 goto failed;
5574 }
5575
Johan Hedberga198e7b2012-02-17 14:27:06 +02005576 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005577 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005578 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5579 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
5580 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005581 goto failed;
5582 }
5583
5584 if (cp->name_known) {
5585 e->name_state = NAME_KNOWN;
5586 list_del(&e->list);
5587 } else {
5588 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02005589 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005590 }
5591
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005592 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
5593 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005594
5595failed:
5596 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005597 return err;
5598}
5599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005600static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005601 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005602{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005603 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005604 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005605 int err;
5606
Marcel Holtmann181d6952020-05-06 09:57:47 +02005607 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005608
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005609 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
5611 MGMT_STATUS_INVALID_PARAMS,
5612 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005613
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005614 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005615
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005616 err = hci_bdaddr_list_add(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005617 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005618 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005619 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005620 goto done;
5621 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005622
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005623 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5624 sk);
5625 status = MGMT_STATUS_SUCCESS;
5626
5627done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005628 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
5629 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005630
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005631 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005632
5633 return err;
5634}
5635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005636static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005637 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005638{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005639 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005640 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005641 int err;
5642
Marcel Holtmann181d6952020-05-06 09:57:47 +02005643 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005644
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005645 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005646 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5647 MGMT_STATUS_INVALID_PARAMS,
5648 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005649
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005650 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005651
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08005652 err = hci_bdaddr_list_del(&hdev->reject_list, &cp->addr.bdaddr,
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005653 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005654 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005655 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005656 goto done;
5657 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005658
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005659 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5660 sk);
5661 status = MGMT_STATUS_SUCCESS;
5662
5663done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005664 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5665 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005666
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005667 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005668
5669 return err;
5670}
5671
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005672static int set_device_id_sync(struct hci_dev *hdev, void *data)
5673{
5674 return hci_update_eir_sync(hdev);
5675}
5676
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005677static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5678 u16 len)
5679{
5680 struct mgmt_cp_set_device_id *cp = data;
5681 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005682 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005683
Marcel Holtmann181d6952020-05-06 09:57:47 +02005684 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005685
Szymon Jancc72d4b82012-03-16 16:02:57 +01005686 source = __le16_to_cpu(cp->source);
5687
5688 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005689 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5690 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005691
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005692 hci_dev_lock(hdev);
5693
Szymon Jancc72d4b82012-03-16 16:02:57 +01005694 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005695 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5696 hdev->devid_product = __le16_to_cpu(cp->product);
5697 hdev->devid_version = __le16_to_cpu(cp->version);
5698
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005699 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5700 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005701
Luiz Augusto von Dentz161510c2021-10-27 16:58:39 -07005702 hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005703
5704 hci_dev_unlock(hdev);
5705
5706 return err;
5707}
5708
Brian Gix26ac4c52021-10-27 16:58:56 -07005709static void enable_advertising_instance(struct hci_dev *hdev, int err)
Arman Uguray24b4f382015-03-23 15:57:12 -07005710{
Brian Gix26ac4c52021-10-27 16:58:56 -07005711 if (err)
5712 bt_dev_err(hdev, "failed to re-configure advertising %d", err);
5713 else
5714 bt_dev_dbg(hdev, "status %d", err);
Arman Uguray24b4f382015-03-23 15:57:12 -07005715}
5716
Brian Gix26ac4c52021-10-27 16:58:56 -07005717static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg4375f102013-09-25 13:26:10 +03005718{
5719 struct cmd_lookup match = { NULL, hdev };
Florian Grandel7816b822015-06-18 03:16:45 +02005720 u8 instance;
5721 struct adv_info *adv_instance;
Brian Gix26ac4c52021-10-27 16:58:56 -07005722 u8 status = mgmt_status(err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305723
Johan Hedberg4375f102013-09-25 13:26:10 +03005724 if (status) {
Johan Hedberg4375f102013-09-25 13:26:10 +03005725 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
Brian Gix26ac4c52021-10-27 16:58:56 -07005726 cmd_status_rsp, &status);
5727 return;
Johan Hedberg4375f102013-09-25 13:26:10 +03005728 }
5729
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005730 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005731 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005732 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005733 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005734
Johan Hedberg4375f102013-09-25 13:26:10 +03005735 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5736 &match);
5737
5738 new_settings(hdev, match.sk);
5739
5740 if (match.sk)
5741 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305742
Arman Uguray24b4f382015-03-23 15:57:12 -07005743 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005744 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005745 */
5746 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005747 list_empty(&hdev->adv_instances))
Brian Gix26ac4c52021-10-27 16:58:56 -07005748 return;
Arman Uguray24b4f382015-03-23 15:57:12 -07005749
Florian Grandel7816b822015-06-18 03:16:45 +02005750 instance = hdev->cur_adv_instance;
5751 if (!instance) {
5752 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5753 struct adv_info, list);
5754 if (!adv_instance)
Brian Gix26ac4c52021-10-27 16:58:56 -07005755 return;
Florian Grandel7816b822015-06-18 03:16:45 +02005756
5757 instance = adv_instance->instance;
5758 }
5759
Brian Gix26ac4c52021-10-27 16:58:56 -07005760 err = hci_schedule_adv_instance_sync(hdev, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005761
Brian Gix26ac4c52021-10-27 16:58:56 -07005762 enable_advertising_instance(hdev, err);
5763}
Arman Uguray24b4f382015-03-23 15:57:12 -07005764
Brian Gix26ac4c52021-10-27 16:58:56 -07005765static int set_adv_sync(struct hci_dev *hdev, void *data)
5766{
5767 struct mgmt_pending_cmd *cmd = data;
5768 struct mgmt_mode *cp = cmd->param;
5769 u8 val = !!cp->val;
Florian Grandel7816b822015-06-18 03:16:45 +02005770
Brian Gix26ac4c52021-10-27 16:58:56 -07005771 if (cp->val == 0x02)
5772 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
5773 else
5774 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Arman Uguray24b4f382015-03-23 15:57:12 -07005775
Brian Gix26ac4c52021-10-27 16:58:56 -07005776 cancel_adv_timeout(hdev);
5777
5778 if (val) {
5779 /* Switch to instance "0" for the Set Advertising setting.
5780 * We cannot use update_[adv|scan_rsp]_data() here as the
5781 * HCI_ADVERTISING flag is not yet set.
5782 */
5783 hdev->cur_adv_instance = 0x00;
5784
5785 if (ext_adv_capable(hdev)) {
5786 hci_start_ext_adv_sync(hdev, 0x00);
5787 } else {
5788 hci_update_adv_data_sync(hdev, 0x00);
5789 hci_update_scan_rsp_data_sync(hdev, 0x00);
5790 hci_enable_advertising_sync(hdev);
5791 }
5792 } else {
5793 hci_disable_advertising_sync(hdev);
5794 }
5795
5796 return 0;
Johan Hedberg4375f102013-09-25 13:26:10 +03005797}
5798
Marcel Holtmann21b51872013-10-10 09:47:53 -07005799static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5800 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005801{
5802 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005803 struct mgmt_pending_cmd *cmd;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005804 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005805 int err;
5806
Marcel Holtmann181d6952020-05-06 09:57:47 +02005807 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005808
Johan Hedberge6fe7982013-10-02 15:45:22 +03005809 status = mgmt_le_support(hdev);
5810 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005811 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5812 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005813
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005814 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5816 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005817
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005818 if (hdev->advertising_paused)
5819 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5820 MGMT_STATUS_BUSY);
5821
Johan Hedberg4375f102013-09-25 13:26:10 +03005822 hci_dev_lock(hdev);
5823
5824 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005825
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005826 /* The following conditions are ones which mean that we should
5827 * not do any HCI communication but directly send a mgmt
5828 * response to user space (after toggling the flag if
5829 * necessary).
5830 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005831 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005832 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5833 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005834 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005835 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005836 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005837 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005838
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005839 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005840 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005841 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005842 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005843 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005844 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005845 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005846 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005847 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005848 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005849 }
5850
5851 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5852 if (err < 0)
5853 goto unlock;
5854
5855 if (changed)
5856 err = new_settings(hdev, sk);
5857
5858 goto unlock;
5859 }
5860
Johan Hedberg333ae952015-03-17 13:48:47 +02005861 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5862 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005863 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5864 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005865 goto unlock;
5866 }
5867
5868 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
Brian Gix26ac4c52021-10-27 16:58:56 -07005869 if (!cmd)
Johan Hedberg4375f102013-09-25 13:26:10 +03005870 err = -ENOMEM;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005871 else
Brian Gix26ac4c52021-10-27 16:58:56 -07005872 err = hci_cmd_sync_queue(hdev, set_adv_sync, cmd,
5873 set_advertising_complete);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005874
Brian Gix26ac4c52021-10-27 16:58:56 -07005875 if (err < 0 && cmd)
Johan Hedberg4375f102013-09-25 13:26:10 +03005876 mgmt_pending_remove(cmd);
5877
5878unlock:
5879 hci_dev_unlock(hdev);
5880 return err;
5881}
5882
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005883static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5884 void *data, u16 len)
5885{
5886 struct mgmt_cp_set_static_address *cp = data;
5887 int err;
5888
Marcel Holtmann181d6952020-05-06 09:57:47 +02005889 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005890
Marcel Holtmann62af4442013-10-02 22:10:32 -07005891 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005892 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5893 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005894
5895 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005896 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5897 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005898
5899 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5900 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005901 return mgmt_cmd_status(sk, hdev->id,
5902 MGMT_OP_SET_STATIC_ADDRESS,
5903 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005904
5905 /* Two most significant bits shall be set */
5906 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005907 return mgmt_cmd_status(sk, hdev->id,
5908 MGMT_OP_SET_STATIC_ADDRESS,
5909 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005910 }
5911
5912 hci_dev_lock(hdev);
5913
5914 bacpy(&hdev->static_addr, &cp->bdaddr);
5915
Marcel Holtmann93690c22015-03-06 10:11:21 -08005916 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5917 if (err < 0)
5918 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005919
Marcel Holtmann93690c22015-03-06 10:11:21 -08005920 err = new_settings(hdev, sk);
5921
5922unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005923 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005924 return err;
5925}
5926
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005927static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5928 void *data, u16 len)
5929{
5930 struct mgmt_cp_set_scan_params *cp = data;
5931 __u16 interval, window;
5932 int err;
5933
Marcel Holtmann181d6952020-05-06 09:57:47 +02005934 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005935
5936 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005937 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5938 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005939
5940 interval = __le16_to_cpu(cp->interval);
5941
5942 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005943 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5944 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005945
5946 window = __le16_to_cpu(cp->window);
5947
5948 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005949 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5950 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005951
Marcel Holtmann899e1072013-10-14 09:55:32 -07005952 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5954 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005955
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005956 hci_dev_lock(hdev);
5957
5958 hdev->le_scan_interval = interval;
5959 hdev->le_scan_window = window;
5960
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005961 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5962 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005963
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005964 /* If background scan is running, restart it so new parameters are
5965 * loaded.
5966 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005967 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Luiz Augusto von Dentzabfeea42021-10-27 16:58:45 -07005968 hdev->discovery.state == DISCOVERY_STOPPED)
5969 hci_update_passive_scan(hdev);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005970
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005971 hci_dev_unlock(hdev);
5972
5973 return err;
5974}
5975
Brian Gix353a0242021-10-27 16:58:46 -07005976static void fast_connectable_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005977{
Brian Gix353a0242021-10-27 16:58:46 -07005978 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005979
Brian Gix353a0242021-10-27 16:58:46 -07005980 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005981
Brian Gix353a0242021-10-27 16:58:46 -07005982 if (err) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005983 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Brian Gix353a0242021-10-27 16:58:46 -07005984 mgmt_status(err));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005985 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005986 struct mgmt_mode *cp = cmd->param;
5987
5988 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005989 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005990 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005991 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005992
Johan Hedberg33e38b32013-03-15 17:07:05 -05005993 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5994 new_settings(hdev, cmd->sk);
5995 }
5996
Brian Gix353a0242021-10-27 16:58:46 -07005997 mgmt_pending_free(cmd);
5998}
Johan Hedberg33e38b32013-03-15 17:07:05 -05005999
Brian Gix353a0242021-10-27 16:58:46 -07006000static int write_fast_connectable_sync(struct hci_dev *hdev, void *data)
6001{
6002 struct mgmt_pending_cmd *cmd = data;
6003 struct mgmt_mode *cp = cmd->param;
6004
6005 return hci_write_fast_connectable_sync(hdev, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05006006}
6007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006008static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006009 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03006010{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006011 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006012 struct mgmt_pending_cmd *cmd;
Antti Julkuf6422ec2011-06-22 13:11:56 +03006013 int err;
6014
Marcel Holtmann181d6952020-05-06 09:57:47 +02006015 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03006016
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006017 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03006018 hdev->hci_ver < BLUETOOTH_VER_1_2)
Brian Gix353a0242021-10-27 16:58:46 -07006019 return mgmt_cmd_status(sk, hdev->id,
6020 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberga69e8372015-03-06 21:08:53 +02006021 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03006022
Johan Hedberga7e80f22013-01-09 16:05:19 +02006023 if (cp->val != 0x00 && cp->val != 0x01)
Brian Gix353a0242021-10-27 16:58:46 -07006024 return mgmt_cmd_status(sk, hdev->id,
6025 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberga69e8372015-03-06 21:08:53 +02006026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02006027
Antti Julkuf6422ec2011-06-22 13:11:56 +03006028 hci_dev_lock(hdev);
6029
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006030 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Brian Gix353a0242021-10-27 16:58:46 -07006031 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05006032 goto unlock;
6033 }
6034
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006035 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07006036 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Brian Gix353a0242021-10-27 16:58:46 -07006037 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006038 new_settings(hdev, sk);
6039 goto unlock;
6040 }
6041
Brian Gix353a0242021-10-27 16:58:46 -07006042 cmd = mgmt_pending_new(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev, data,
6043 len);
6044 if (!cmd)
Johan Hedberg33e38b32013-03-15 17:07:05 -05006045 err = -ENOMEM;
Brian Gix353a0242021-10-27 16:58:46 -07006046 else
6047 err = hci_cmd_sync_queue(hdev, write_fast_connectable_sync, cmd,
6048 fast_connectable_complete);
Johan Hedberg33e38b32013-03-15 17:07:05 -05006049
Antti Julkuf6422ec2011-06-22 13:11:56 +03006050 if (err < 0) {
Brian Gix353a0242021-10-27 16:58:46 -07006051 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
6052 MGMT_STATUS_FAILED);
6053
Brian Gix353a0242021-10-27 16:58:46 -07006054 if (cmd)
6055 mgmt_pending_free(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03006056 }
6057
Johan Hedberg33e38b32013-03-15 17:07:05 -05006058unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03006059 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05006060
Antti Julkuf6422ec2011-06-22 13:11:56 +03006061 return err;
6062}
6063
Brian Gix451d95a2021-10-27 16:58:47 -07006064static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg0663ca22013-10-02 13:43:14 +03006065{
Brian Gix451d95a2021-10-27 16:58:47 -07006066 struct mgmt_pending_cmd *cmd = data;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006067
Brian Gix451d95a2021-10-27 16:58:47 -07006068 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006069
Brian Gix451d95a2021-10-27 16:58:47 -07006070 if (err) {
6071 u8 mgmt_err = mgmt_status(err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006072
6073 /* We need to restore the flag if related HCI commands
6074 * failed.
6075 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006076 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006077
Johan Hedberga69e8372015-03-06 21:08:53 +02006078 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006079 } else {
6080 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
6081 new_settings(hdev, cmd->sk);
6082 }
6083
Brian Gix451d95a2021-10-27 16:58:47 -07006084 mgmt_pending_free(cmd);
6085}
Johan Hedberg0663ca22013-10-02 13:43:14 +03006086
Brian Gix451d95a2021-10-27 16:58:47 -07006087static int set_bredr_sync(struct hci_dev *hdev, void *data)
6088{
6089 int status;
6090
6091 status = hci_write_fast_connectable_sync(hdev, false);
6092
6093 if (!status)
6094 status = hci_update_scan_sync(hdev);
6095
6096 /* Since only the advertising data flags will change, there
6097 * is no need to update the scan response data.
6098 */
6099 if (!status)
6100 status = hci_update_adv_data_sync(hdev, hdev->cur_adv_instance);
6101
6102 return status;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006103}
6104
6105static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
6106{
6107 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006108 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03006109 int err;
6110
Marcel Holtmann181d6952020-05-06 09:57:47 +02006111 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006112
6113 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006114 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6115 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006116
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006117 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006118 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6119 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006120
6121 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006122 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6123 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006124
6125 hci_dev_lock(hdev);
6126
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006127 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03006128 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6129 goto unlock;
6130 }
6131
6132 if (!hdev_is_powered(hdev)) {
6133 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006134 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
6135 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
6136 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
6137 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
6138 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006139 }
6140
Marcel Holtmannce05d602015-03-13 02:11:03 -07006141 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006142
6143 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
6144 if (err < 0)
6145 goto unlock;
6146
6147 err = new_settings(hdev, sk);
6148 goto unlock;
6149 }
6150
6151 /* Reject disabling when powered on */
6152 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006153 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6154 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006155 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006156 } else {
6157 /* When configuring a dual-mode controller to operate
6158 * with LE only and using a static address, then switching
6159 * BR/EDR back on is not allowed.
6160 *
6161 * Dual-mode controllers shall operate with the public
6162 * address as its identity address for BR/EDR and LE. So
6163 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006164 *
6165 * The same restrictions applies when secure connections
6166 * has been enabled. For BR/EDR this is a controller feature
6167 * while for LE it is a host stack feature. This means that
6168 * switching BR/EDR back on when secure connections has been
6169 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006170 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006171 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08006172 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006173 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006174 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6175 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08006176 goto unlock;
6177 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03006178 }
6179
Brian Gix451d95a2021-10-27 16:58:47 -07006180 cmd = mgmt_pending_new(sk, MGMT_OP_SET_BREDR, hdev, data, len);
6181 if (!cmd)
Johan Hedberg0663ca22013-10-02 13:43:14 +03006182 err = -ENOMEM;
Brian Gix451d95a2021-10-27 16:58:47 -07006183 else
6184 err = hci_cmd_sync_queue(hdev, set_bredr_sync, cmd,
6185 set_bredr_complete);
6186
6187 if (err < 0) {
6188 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
6189 MGMT_STATUS_FAILED);
6190 if (cmd)
6191 mgmt_pending_free(cmd);
6192
Johan Hedberg0663ca22013-10-02 13:43:14 +03006193 goto unlock;
6194 }
6195
Johan Hedbergf2252572015-11-18 12:49:20 +02006196 /* We need to flip the bit already here so that
6197 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03006198 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006199 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03006200
Johan Hedberg0663ca22013-10-02 13:43:14 +03006201unlock:
6202 hci_dev_unlock(hdev);
6203 return err;
6204}
6205
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006206static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberga1443f52015-01-23 15:42:46 +02006207{
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006208 struct mgmt_pending_cmd *cmd = data;
Johan Hedberga1443f52015-01-23 15:42:46 +02006209 struct mgmt_mode *cp;
6210
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006211 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberga1443f52015-01-23 15:42:46 +02006212
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006213 if (err) {
6214 u8 mgmt_err = mgmt_status(err);
Johan Hedberga1443f52015-01-23 15:42:46 +02006215
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006216 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
6217 goto done;
Johan Hedberga1443f52015-01-23 15:42:46 +02006218 }
6219
6220 cp = cmd->param;
6221
6222 switch (cp->val) {
6223 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006224 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
6225 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006226 break;
6227 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006228 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006229 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006230 break;
6231 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006232 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
6233 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02006234 break;
6235 }
6236
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006237 send_settings_rsp(cmd->sk, cmd->opcode, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02006238 new_settings(hdev, cmd->sk);
6239
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006240done:
6241 mgmt_pending_free(cmd);
6242}
6243
6244static int set_secure_conn_sync(struct hci_dev *hdev, void *data)
6245{
6246 struct mgmt_pending_cmd *cmd = data;
6247 struct mgmt_mode *cp = cmd->param;
6248 u8 val = !!cp->val;
6249
6250 /* Force write of val */
6251 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
6252
6253 return hci_write_sc_support_sync(hdev, val);
Johan Hedberga1443f52015-01-23 15:42:46 +02006254}
6255
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006256static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
6257 void *data, u16 len)
6258{
6259 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006260 struct mgmt_pending_cmd *cmd;
Johan Hedberga3209692014-05-26 11:23:35 +03006261 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006262 int err;
6263
Marcel Holtmann181d6952020-05-06 09:57:47 +02006264 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006265
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006266 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006267 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006268 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6269 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006270
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006271 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02006272 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006273 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02006274 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6275 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08006276
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006277 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006278 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006279 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006280
6281 hci_dev_lock(hdev);
6282
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08006283 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006284 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006285 bool changed;
6286
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006287 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006288 changed = !hci_dev_test_and_set_flag(hdev,
6289 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006290 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006291 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006292 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006293 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006294 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006295 changed = hci_dev_test_and_clear_flag(hdev,
6296 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006297 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006298 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006299
6300 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6301 if (err < 0)
6302 goto failed;
6303
6304 if (changed)
6305 err = new_settings(hdev, sk);
6306
6307 goto failed;
6308 }
6309
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08006310 val = !!cp->val;
6311
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006312 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6313 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006314 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
6315 goto failed;
6316 }
6317
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006318 cmd = mgmt_pending_new(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
6319 if (!cmd)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006320 err = -ENOMEM;
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006321 else
6322 err = hci_cmd_sync_queue(hdev, set_secure_conn_sync, cmd,
6323 set_secure_conn_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006324
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006325 if (err < 0) {
Brian Gix2f2eb0c2021-10-27 16:58:49 -07006326 mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
6327 MGMT_STATUS_FAILED);
6328 if (cmd)
6329 mgmt_pending_free(cmd);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08006330 }
6331
6332failed:
6333 hci_dev_unlock(hdev);
6334 return err;
6335}
6336
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006337static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
6338 void *data, u16 len)
6339{
6340 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03006341 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006342 int err;
6343
Marcel Holtmann181d6952020-05-06 09:57:47 +02006344 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006345
Johan Hedbergb97109792014-06-24 14:00:28 +03006346 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006347 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
6348 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006349
6350 hci_dev_lock(hdev);
6351
6352 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07006353 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006354 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006355 changed = hci_dev_test_and_clear_flag(hdev,
6356 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006357
Johan Hedbergb97109792014-06-24 14:00:28 +03006358 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07006359 use_changed = !hci_dev_test_and_set_flag(hdev,
6360 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006361 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006362 use_changed = hci_dev_test_and_clear_flag(hdev,
6363 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006364
6365 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006366 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03006367 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
6368 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
6369 sizeof(mode), &mode);
6370 }
6371
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006372 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
6373 if (err < 0)
6374 goto unlock;
6375
6376 if (changed)
6377 err = new_settings(hdev, sk);
6378
6379unlock:
6380 hci_dev_unlock(hdev);
6381 return err;
6382}
6383
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006384static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6385 u16 len)
6386{
6387 struct mgmt_cp_set_privacy *cp = cp_data;
6388 bool changed;
6389 int err;
6390
Marcel Holtmann181d6952020-05-06 09:57:47 +02006391 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006392
6393 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006394 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6395 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006396
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006397 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006398 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006400
6401 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006402 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6403 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006404
6405 hci_dev_lock(hdev);
6406
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006407 /* If user space supports this command it is also expected to
6408 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
6409 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006410 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006411
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006412 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006413 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006414 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006415 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306416 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006417 if (cp->privacy == 0x02)
6418 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
6419 else
6420 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006421 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006422 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006423 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006424 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306425 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006426 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006427 }
6428
6429 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
6430 if (err < 0)
6431 goto unlock;
6432
6433 if (changed)
6434 err = new_settings(hdev, sk);
6435
6436unlock:
6437 hci_dev_unlock(hdev);
6438 return err;
6439}
6440
Johan Hedberg41edf162014-02-18 10:19:35 +02006441static bool irk_is_valid(struct mgmt_irk_info *irk)
6442{
6443 switch (irk->addr.type) {
6444 case BDADDR_LE_PUBLIC:
6445 return true;
6446
6447 case BDADDR_LE_RANDOM:
6448 /* Two most significant bits shall be set */
6449 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6450 return false;
6451 return true;
6452 }
6453
6454 return false;
6455}
6456
6457static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6458 u16 len)
6459{
6460 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006461 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
6462 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02006463 u16 irk_count, expected_len;
6464 int i, err;
6465
Marcel Holtmann181d6952020-05-06 09:57:47 +02006466 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02006467
6468 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006469 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6470 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02006471
6472 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006473 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006474 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
6475 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006476 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6477 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006478 }
Johan Hedberg41edf162014-02-18 10:19:35 +02006479
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006480 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006481 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006482 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
6483 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006484 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6485 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006486 }
6487
Marcel Holtmann181d6952020-05-06 09:57:47 +02006488 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006489
6490 for (i = 0; i < irk_count; i++) {
6491 struct mgmt_irk_info *key = &cp->irks[i];
6492
6493 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006494 return mgmt_cmd_status(sk, hdev->id,
6495 MGMT_OP_LOAD_IRKS,
6496 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006497 }
6498
6499 hci_dev_lock(hdev);
6500
6501 hci_smp_irks_clear(hdev);
6502
6503 for (i = 0; i < irk_count; i++) {
6504 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02006505
Alain Michaud600a8742020-01-07 00:43:17 +00006506 if (hci_is_blocked_key(hdev,
6507 HCI_BLOCKED_KEY_TYPE_IRK,
6508 irk->val)) {
6509 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
6510 &irk->addr.bdaddr);
6511 continue;
6512 }
6513
Johan Hedberg85813a72015-10-21 18:02:59 +03006514 hci_add_irk(hdev, &irk->addr.bdaddr,
6515 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02006516 BDADDR_ANY);
6517 }
6518
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006519 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02006520
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006521 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02006522
6523 hci_dev_unlock(hdev);
6524
6525 return err;
6526}
6527
Johan Hedberg3f706b72013-01-20 14:27:16 +02006528static bool ltk_is_valid(struct mgmt_ltk_info *key)
6529{
Archie Pusakafad646e2021-05-31 16:37:25 +08006530 if (key->initiator != 0x00 && key->initiator != 0x01)
Johan Hedberg3f706b72013-01-20 14:27:16 +02006531 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08006532
6533 switch (key->addr.type) {
6534 case BDADDR_LE_PUBLIC:
6535 return true;
6536
6537 case BDADDR_LE_RANDOM:
6538 /* Two most significant bits shall be set */
6539 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6540 return false;
6541 return true;
6542 }
6543
6544 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02006545}
6546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006547static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006548 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006549{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006550 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006551 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
6552 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006553 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006554 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006555
Marcel Holtmann181d6952020-05-06 09:57:47 +02006556 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006557
6558 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006559 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6560 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006561
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006562 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006563 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006564 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
6565 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006568 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006569
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006570 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006571 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006572 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
6573 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006574 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6575 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006576 }
6577
Marcel Holtmann181d6952020-05-06 09:57:47 +02006578 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006579
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006580 for (i = 0; i < key_count; i++) {
6581 struct mgmt_ltk_info *key = &cp->keys[i];
6582
Johan Hedberg3f706b72013-01-20 14:27:16 +02006583 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006584 return mgmt_cmd_status(sk, hdev->id,
6585 MGMT_OP_LOAD_LONG_TERM_KEYS,
6586 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006587 }
6588
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006589 hci_dev_lock(hdev);
6590
6591 hci_smp_ltks_clear(hdev);
6592
6593 for (i = 0; i < key_count; i++) {
6594 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006595 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006596
Alain Michaud600a8742020-01-07 00:43:17 +00006597 if (hci_is_blocked_key(hdev,
6598 HCI_BLOCKED_KEY_TYPE_LTK,
6599 key->val)) {
6600 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6601 &key->addr.bdaddr);
6602 continue;
6603 }
6604
Johan Hedberg61b43352014-05-29 19:36:53 +03006605 switch (key->type) {
6606 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006607 authenticated = 0x00;
Archie Pusakafad646e2021-05-31 16:37:25 +08006608 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006609 break;
6610 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006611 authenticated = 0x01;
Archie Pusakafad646e2021-05-31 16:37:25 +08006612 type = key->initiator ? SMP_LTK : SMP_LTK_RESPONDER;
Johan Hedberg61b43352014-05-29 19:36:53 +03006613 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006614 case MGMT_LTK_P256_UNAUTH:
6615 authenticated = 0x00;
6616 type = SMP_LTK_P256;
6617 break;
6618 case MGMT_LTK_P256_AUTH:
6619 authenticated = 0x01;
6620 type = SMP_LTK_P256;
6621 break;
6622 case MGMT_LTK_P256_DEBUG:
6623 authenticated = 0x00;
6624 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006625 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006626 default:
6627 continue;
6628 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006629
Johan Hedberg85813a72015-10-21 18:02:59 +03006630 hci_add_ltk(hdev, &key->addr.bdaddr,
6631 le_addr_type(key->addr.type), type, authenticated,
6632 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006633 }
6634
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006635 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006636 NULL, 0);
6637
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006638 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006639
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006640 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006641}
6642
Brian Gix47db6b42021-10-27 16:58:48 -07006643static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006644{
Brian Gix47db6b42021-10-27 16:58:48 -07006645 struct mgmt_pending_cmd *cmd = data;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006646 struct hci_conn *conn = cmd->user_data;
Brian Gix47db6b42021-10-27 16:58:48 -07006647 struct mgmt_cp_get_conn_info *cp = cmd->param;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006648 struct mgmt_rp_get_conn_info rp;
Brian Gix47db6b42021-10-27 16:58:48 -07006649 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006650
Brian Gix47db6b42021-10-27 16:58:48 -07006651 bt_dev_dbg(hdev, "err %d", err);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006652
Brian Gix47db6b42021-10-27 16:58:48 -07006653 memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr));
6654
6655 status = mgmt_status(err);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006656 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006657 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006658 rp.tx_power = conn->tx_power;
6659 rp.max_tx_power = conn->max_tx_power;
6660 } else {
6661 rp.rssi = HCI_RSSI_INVALID;
6662 rp.tx_power = HCI_TX_POWER_INVALID;
6663 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006664 }
6665
Brian Gix47db6b42021-10-27 16:58:48 -07006666 mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
6667 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006668
Brian Gix47db6b42021-10-27 16:58:48 -07006669 if (conn) {
6670 hci_conn_drop(conn);
6671 hci_conn_put(conn);
6672 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006673
Brian Gix47db6b42021-10-27 16:58:48 -07006674 mgmt_pending_free(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006675}
6676
Brian Gix47db6b42021-10-27 16:58:48 -07006677static int get_conn_info_sync(struct hci_dev *hdev, void *data)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006678{
Brian Gix47db6b42021-10-27 16:58:48 -07006679 struct mgmt_pending_cmd *cmd = data;
6680 struct mgmt_cp_get_conn_info *cp = cmd->param;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006681 struct hci_conn *conn;
Brian Gix47db6b42021-10-27 16:58:48 -07006682 int err;
6683 __le16 handle;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006684
Brian Gix47db6b42021-10-27 16:58:48 -07006685 /* Make sure we are still connected */
6686 if (cp->addr.type == BDADDR_BREDR)
6687 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6688 &cp->addr.bdaddr);
6689 else
6690 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006691
Brian Gix47db6b42021-10-27 16:58:48 -07006692 if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) {
6693 if (cmd->user_data) {
6694 hci_conn_drop(cmd->user_data);
6695 hci_conn_put(cmd->user_data);
6696 cmd->user_data = NULL;
6697 }
6698 return MGMT_STATUS_NOT_CONNECTED;
6699 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006700
Brian Gix47db6b42021-10-27 16:58:48 -07006701 handle = cpu_to_le16(conn->handle);
6702
6703 /* Refresh RSSI each time */
6704 err = hci_read_rssi_sync(hdev, handle);
6705
6706 /* For LE links TX power does not change thus we don't need to
6707 * query for it once value is known.
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006708 */
Brian Gix47db6b42021-10-27 16:58:48 -07006709 if (!err && (!bdaddr_type_is_le(cp->addr.type) ||
6710 conn->tx_power == HCI_TX_POWER_INVALID))
6711 err = hci_read_tx_power_sync(hdev, handle, 0x00);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006712
Brian Gix47db6b42021-10-27 16:58:48 -07006713 /* Max TX power needs to be read only once per connection */
6714 if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID)
6715 err = hci_read_tx_power_sync(hdev, handle, 0x01);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006716
Brian Gix47db6b42021-10-27 16:58:48 -07006717 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006718}
6719
6720static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6721 u16 len)
6722{
6723 struct mgmt_cp_get_conn_info *cp = data;
6724 struct mgmt_rp_get_conn_info rp;
6725 struct hci_conn *conn;
6726 unsigned long conn_info_age;
6727 int err = 0;
6728
Marcel Holtmann181d6952020-05-06 09:57:47 +02006729 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006730
6731 memset(&rp, 0, sizeof(rp));
6732 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6733 rp.addr.type = cp->addr.type;
6734
6735 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006736 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6737 MGMT_STATUS_INVALID_PARAMS,
6738 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006739
6740 hci_dev_lock(hdev);
6741
6742 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006743 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6744 MGMT_STATUS_NOT_POWERED, &rp,
6745 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006746 goto unlock;
6747 }
6748
6749 if (cp->addr.type == BDADDR_BREDR)
6750 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6751 &cp->addr.bdaddr);
6752 else
6753 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6754
6755 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006756 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6757 MGMT_STATUS_NOT_CONNECTED, &rp,
6758 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006759 goto unlock;
6760 }
6761
6762 /* To avoid client trying to guess when to poll again for information we
6763 * calculate conn info age as random value between min/max set in hdev.
6764 */
6765 conn_info_age = hdev->conn_info_min_age +
6766 prandom_u32_max(hdev->conn_info_max_age -
6767 hdev->conn_info_min_age);
6768
6769 /* Query controller to refresh cached values if they are too old or were
6770 * never read.
6771 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006772 if (time_after(jiffies, conn->conn_info_timestamp +
6773 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006774 !conn->conn_info_timestamp) {
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006775 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006776
Brian Gix47db6b42021-10-27 16:58:48 -07006777 cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data,
6778 len);
6779 if (!cmd)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006780 err = -ENOMEM;
Brian Gix47db6b42021-10-27 16:58:48 -07006781 else
6782 err = hci_cmd_sync_queue(hdev, get_conn_info_sync,
6783 cmd, get_conn_info_complete);
6784
6785 if (err < 0) {
6786 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6787 MGMT_STATUS_FAILED, &rp, sizeof(rp));
6788
6789 if (cmd)
6790 mgmt_pending_free(cmd);
6791
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006792 goto unlock;
6793 }
6794
6795 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006796 cmd->user_data = hci_conn_get(conn);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006797
6798 conn->conn_info_timestamp = jiffies;
6799 } else {
6800 /* Cache is valid, just reply with values cached in hci_conn */
6801 rp.rssi = conn->rssi;
6802 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006803 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006804
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006805 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6806 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006807 }
6808
6809unlock:
6810 hci_dev_unlock(hdev);
6811 return err;
6812}
6813
Brian Gix5a750132021-10-27 16:58:50 -07006814static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
Johan Hedberg69487372014-12-05 13:36:07 +02006815{
Brian Gix5a750132021-10-27 16:58:50 -07006816 struct mgmt_pending_cmd *cmd = data;
6817 struct mgmt_cp_get_clock_info *cp = cmd->param;
Johan Hedberg69487372014-12-05 13:36:07 +02006818 struct mgmt_rp_get_clock_info rp;
Brian Gix5a750132021-10-27 16:58:50 -07006819 struct hci_conn *conn = cmd->user_data;
6820 u8 status = mgmt_status(err);
6821
6822 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg69487372014-12-05 13:36:07 +02006823
6824 memset(&rp, 0, sizeof(rp));
Brian Gix5a750132021-10-27 16:58:50 -07006825 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6826 rp.addr.type = cp->addr.type;
Johan Hedberg69487372014-12-05 13:36:07 +02006827
Brian Gix5a750132021-10-27 16:58:50 -07006828 if (err)
Johan Hedberg69487372014-12-05 13:36:07 +02006829 goto complete;
6830
Brian Gix5a750132021-10-27 16:58:50 -07006831 rp.local_clock = cpu_to_le32(hdev->clock);
Johan Hedberg69487372014-12-05 13:36:07 +02006832
6833 if (conn) {
6834 rp.piconet_clock = cpu_to_le32(conn->clock);
6835 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
Brian Gix5a750132021-10-27 16:58:50 -07006836 hci_conn_drop(conn);
6837 hci_conn_put(conn);
Johan Hedberg69487372014-12-05 13:36:07 +02006838 }
6839
6840complete:
Brian Gix5a750132021-10-27 16:58:50 -07006841 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6842 sizeof(rp));
6843
6844 mgmt_pending_free(cmd);
6845}
6846
6847static int get_clock_info_sync(struct hci_dev *hdev, void *data)
6848{
6849 struct mgmt_pending_cmd *cmd = data;
6850 struct mgmt_cp_get_clock_info *cp = cmd->param;
6851 struct hci_cp_read_clock hci_cp;
6852 struct hci_conn *conn = cmd->user_data;
6853 int err;
6854
6855 memset(&hci_cp, 0, sizeof(hci_cp));
6856 err = hci_read_clock_sync(hdev, &hci_cp);
Johan Hedberg69487372014-12-05 13:36:07 +02006857
6858 if (conn) {
Brian Gix5a750132021-10-27 16:58:50 -07006859 /* Make sure connection still exists */
6860 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6861 &cp->addr.bdaddr);
6862
6863 if (conn && conn == cmd->user_data &&
6864 conn->state == BT_CONNECTED) {
6865 hci_cp.handle = cpu_to_le16(conn->handle);
6866 hci_cp.which = 0x01; /* Piconet clock */
6867 err = hci_read_clock_sync(hdev, &hci_cp);
6868 } else if (cmd->user_data) {
6869 hci_conn_drop(cmd->user_data);
6870 hci_conn_put(cmd->user_data);
6871 cmd->user_data = NULL;
6872 }
Johan Hedberg69487372014-12-05 13:36:07 +02006873 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006874
6875 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006876}
6877
Johan Hedberg95868422014-06-28 17:54:07 +03006878static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
Brian Gix5a750132021-10-27 16:58:50 -07006879 u16 len)
Johan Hedberg95868422014-06-28 17:54:07 +03006880{
6881 struct mgmt_cp_get_clock_info *cp = data;
6882 struct mgmt_rp_get_clock_info rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006883 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006884 struct hci_conn *conn;
6885 int err;
6886
Marcel Holtmann181d6952020-05-06 09:57:47 +02006887 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006888
6889 memset(&rp, 0, sizeof(rp));
6890 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6891 rp.addr.type = cp->addr.type;
6892
6893 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006894 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6895 MGMT_STATUS_INVALID_PARAMS,
6896 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006897
6898 hci_dev_lock(hdev);
6899
6900 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006901 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6902 MGMT_STATUS_NOT_POWERED, &rp,
6903 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006904 goto unlock;
6905 }
6906
6907 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6908 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6909 &cp->addr.bdaddr);
6910 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006911 err = mgmt_cmd_complete(sk, hdev->id,
6912 MGMT_OP_GET_CLOCK_INFO,
6913 MGMT_STATUS_NOT_CONNECTED,
6914 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006915 goto unlock;
6916 }
6917 } else {
6918 conn = NULL;
6919 }
6920
Brian Gix5a750132021-10-27 16:58:50 -07006921 cmd = mgmt_pending_new(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6922 if (!cmd)
Johan Hedberg95868422014-06-28 17:54:07 +03006923 err = -ENOMEM;
Brian Gix5a750132021-10-27 16:58:50 -07006924 else
6925 err = hci_cmd_sync_queue(hdev, get_clock_info_sync, cmd,
6926 get_clock_info_complete);
Johan Hedberg95868422014-06-28 17:54:07 +03006927
Brian Gix5a750132021-10-27 16:58:50 -07006928 if (err < 0) {
6929 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6930 MGMT_STATUS_FAILED, &rp, sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006931
Brian Gix5a750132021-10-27 16:58:50 -07006932 if (cmd)
6933 mgmt_pending_free(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006934
Brian Gix5a750132021-10-27 16:58:50 -07006935 } else if (conn) {
Johan Hedberg95868422014-06-28 17:54:07 +03006936 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006937 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006938 }
6939
Johan Hedberg95868422014-06-28 17:54:07 +03006940
6941unlock:
6942 hci_dev_unlock(hdev);
6943 return err;
6944}
6945
Johan Hedberg5a154e62014-12-19 22:26:02 +02006946static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6947{
6948 struct hci_conn *conn;
6949
6950 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6951 if (!conn)
6952 return false;
6953
6954 if (conn->dst_type != type)
6955 return false;
6956
6957 if (conn->state != BT_CONNECTED)
6958 return false;
6959
6960 return true;
6961}
6962
6963/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006964static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006965 u8 addr_type, u8 auto_connect)
6966{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006967 struct hci_conn_params *params;
6968
6969 params = hci_conn_params_add(hdev, addr, addr_type);
6970 if (!params)
6971 return -EIO;
6972
6973 if (params->auto_connect == auto_connect)
6974 return 0;
6975
6976 list_del_init(&params->action);
6977
6978 switch (auto_connect) {
6979 case HCI_AUTO_CONN_DISABLED:
6980 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006981 /* If auto connect is being disabled when we're trying to
6982 * connect to device, keep connecting.
6983 */
6984 if (params->explicit_connect)
6985 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006986 break;
6987 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006988 if (params->explicit_connect)
6989 list_add(&params->action, &hdev->pend_le_conns);
6990 else
6991 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006992 break;
6993 case HCI_AUTO_CONN_DIRECT:
6994 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006995 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006996 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006997 break;
6998 }
6999
7000 params->auto_connect = auto_connect;
7001
Marcel Holtmann181d6952020-05-06 09:57:47 +02007002 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
7003 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02007004
7005 return 0;
7006}
7007
Marcel Holtmann8afef092014-06-29 22:28:34 +02007008static void device_added(struct sock *sk, struct hci_dev *hdev,
7009 bdaddr_t *bdaddr, u8 type, u8 action)
7010{
7011 struct mgmt_ev_device_added ev;
7012
7013 bacpy(&ev.addr.bdaddr, bdaddr);
7014 ev.addr.type = type;
7015 ev.action = action;
7016
7017 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
7018}
7019
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007020static int add_device_sync(struct hci_dev *hdev, void *data)
7021{
7022 return hci_update_passive_scan_sync(hdev);
7023}
7024
Marcel Holtmann2faade52014-06-29 19:44:03 +02007025static int add_device(struct sock *sk, struct hci_dev *hdev,
7026 void *data, u16 len)
7027{
7028 struct mgmt_cp_add_device *cp = data;
7029 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007030 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007031 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007032 u32 current_flags = 0;
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08007033 u32 supported_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007034
Marcel Holtmann181d6952020-05-06 09:57:47 +02007035 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007036
Johan Hedberg66593582014-07-09 12:59:14 +03007037 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02007038 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007039 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7040 MGMT_STATUS_INVALID_PARAMS,
7041 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007042
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007043 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007044 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7045 MGMT_STATUS_INVALID_PARAMS,
7046 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007047
7048 hci_dev_lock(hdev);
7049
Johan Hedberg66593582014-07-09 12:59:14 +03007050 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007051 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03007052 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007053 err = mgmt_cmd_complete(sk, hdev->id,
7054 MGMT_OP_ADD_DEVICE,
7055 MGMT_STATUS_INVALID_PARAMS,
7056 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007057 goto unlock;
7058 }
7059
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007060 err = hci_bdaddr_list_add_with_flags(&hdev->accept_list,
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02007061 &cp->addr.bdaddr,
7062 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03007063 if (err)
7064 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03007065
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007066 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007067
Johan Hedberg66593582014-07-09 12:59:14 +03007068 goto added;
7069 }
7070
Johan Hedberg85813a72015-10-21 18:02:59 +03007071 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007072
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007073 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02007074 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007075 else if (cp->action == 0x01)
7076 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007077 else
Johan Hedberga3451d22014-07-02 17:37:27 +03007078 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007079
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007080 /* Kernel internally uses conn_params with resolvable private
7081 * address, but Add Device allows only identity addresses.
7082 * Make sure it is enforced before calling
7083 * hci_conn_params_lookup.
7084 */
7085 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007086 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7087 MGMT_STATUS_INVALID_PARAMS,
7088 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007089 goto unlock;
7090 }
7091
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02007092 /* If the connection parameters don't exist for this device,
7093 * they will be created and configured with defaults.
7094 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02007095 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02007096 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007097 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7098 MGMT_STATUS_FAILED, &cp->addr,
7099 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007100 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007101 } else {
7102 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7103 addr_type);
7104 if (params)
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08007105 bitmap_to_arr32(&current_flags, params->flags,
7106 __HCI_CONN_NUM_FLAGS);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007107 }
7108
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007109 err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
7110 if (err < 0)
7111 goto unlock;
Johan Hedberg51d7a942015-11-11 08:11:18 +02007112
Johan Hedberg66593582014-07-09 12:59:14 +03007113added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02007114 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08007115 bitmap_to_arr32(&supported_flags, hdev->conn_flags,
7116 __HCI_CONN_NUM_FLAGS);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007117 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
Luiz Augusto von Dentzfe92ee62021-12-01 11:49:50 -08007118 supported_flags, current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007119
Johan Hedberg51d7a942015-11-11 08:11:18 +02007120 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
7121 MGMT_STATUS_SUCCESS, &cp->addr,
7122 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007123
7124unlock:
7125 hci_dev_unlock(hdev);
7126 return err;
7127}
7128
Marcel Holtmann8afef092014-06-29 22:28:34 +02007129static void device_removed(struct sock *sk, struct hci_dev *hdev,
7130 bdaddr_t *bdaddr, u8 type)
7131{
7132 struct mgmt_ev_device_removed ev;
7133
7134 bacpy(&ev.addr.bdaddr, bdaddr);
7135 ev.addr.type = type;
7136
7137 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
7138}
7139
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007140static int remove_device_sync(struct hci_dev *hdev, void *data)
7141{
7142 return hci_update_passive_scan_sync(hdev);
7143}
7144
Marcel Holtmann2faade52014-06-29 19:44:03 +02007145static int remove_device(struct sock *sk, struct hci_dev *hdev,
7146 void *data, u16 len)
7147{
7148 struct mgmt_cp_remove_device *cp = data;
7149 int err;
7150
Marcel Holtmann181d6952020-05-06 09:57:47 +02007151 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007152
7153 hci_dev_lock(hdev);
7154
7155 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03007156 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02007157 u8 addr_type;
7158
Johan Hedberg66593582014-07-09 12:59:14 +03007159 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007160 err = mgmt_cmd_complete(sk, hdev->id,
7161 MGMT_OP_REMOVE_DEVICE,
7162 MGMT_STATUS_INVALID_PARAMS,
7163 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007164 goto unlock;
7165 }
7166
Johan Hedberg66593582014-07-09 12:59:14 +03007167 if (cp->addr.type == BDADDR_BREDR) {
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007168 err = hci_bdaddr_list_del(&hdev->accept_list,
Johan Hedberg66593582014-07-09 12:59:14 +03007169 &cp->addr.bdaddr,
7170 cp->addr.type);
7171 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007172 err = mgmt_cmd_complete(sk, hdev->id,
7173 MGMT_OP_REMOVE_DEVICE,
7174 MGMT_STATUS_INVALID_PARAMS,
7175 &cp->addr,
7176 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03007177 goto unlock;
7178 }
7179
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007180 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007181
Johan Hedberg66593582014-07-09 12:59:14 +03007182 device_removed(sk, hdev, &cp->addr.bdaddr,
7183 cp->addr.type);
7184 goto complete;
7185 }
7186
Johan Hedberg85813a72015-10-21 18:02:59 +03007187 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007188
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007189 /* Kernel internally uses conn_params with resolvable private
7190 * address, but Remove Device allows only identity addresses.
7191 * Make sure it is enforced before calling
7192 * hci_conn_params_lookup.
7193 */
7194 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007195 err = mgmt_cmd_complete(sk, hdev->id,
7196 MGMT_OP_REMOVE_DEVICE,
7197 MGMT_STATUS_INVALID_PARAMS,
7198 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02007199 goto unlock;
7200 }
7201
Johan Hedbergc71593d2014-07-02 17:37:28 +03007202 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
7203 addr_type);
7204 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007205 err = mgmt_cmd_complete(sk, hdev->id,
7206 MGMT_OP_REMOVE_DEVICE,
7207 MGMT_STATUS_INVALID_PARAMS,
7208 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007209 goto unlock;
7210 }
7211
Johan Hedberg679d2b62015-10-16 10:07:52 +03007212 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
7213 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007214 err = mgmt_cmd_complete(sk, hdev->id,
7215 MGMT_OP_REMOVE_DEVICE,
7216 MGMT_STATUS_INVALID_PARAMS,
7217 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03007218 goto unlock;
7219 }
7220
Johan Hedbergd1dbf122014-07-04 16:17:23 +03007221 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03007222 list_del(&params->list);
7223 kfree(params);
Marcel Holtmann8afef092014-06-29 22:28:34 +02007224
7225 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02007226 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03007227 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03007228 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03007229
Marcel Holtmann2faade52014-06-29 19:44:03 +02007230 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02007231 err = mgmt_cmd_complete(sk, hdev->id,
7232 MGMT_OP_REMOVE_DEVICE,
7233 MGMT_STATUS_INVALID_PARAMS,
7234 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007235 goto unlock;
7236 }
7237
Archie Pusaka3d4f9c02021-06-04 16:26:27 +08007238 list_for_each_entry_safe(b, btmp, &hdev->accept_list, list) {
Johan Hedberg66593582014-07-09 12:59:14 +03007239 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
7240 list_del(&b->list);
7241 kfree(b);
7242 }
7243
Johan Hedberg01b1cb82015-11-16 12:52:21 +02007244 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03007245
Johan Hedberg19de0822014-07-06 13:06:51 +03007246 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
7247 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
7248 continue;
7249 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03007250 if (p->explicit_connect) {
7251 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
7252 continue;
7253 }
Johan Hedberg19de0822014-07-06 13:06:51 +03007254 list_del(&p->action);
7255 list_del(&p->list);
7256 kfree(p);
7257 }
7258
Marcel Holtmann181d6952020-05-06 09:57:47 +02007259 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Marcel Holtmann2faade52014-06-29 19:44:03 +02007260 }
7261
Luiz Augusto von Dentze8907f72021-10-27 16:58:41 -07007262 hci_cmd_sync_queue(hdev, remove_device_sync, NULL, NULL);
7263
Johan Hedberg66593582014-07-09 12:59:14 +03007264complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02007265 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
7266 MGMT_STATUS_SUCCESS, &cp->addr,
7267 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02007268unlock:
7269 hci_dev_unlock(hdev);
7270 return err;
7271}
7272
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007273static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
7274 u16 len)
7275{
7276 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03007277 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
7278 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007279 u16 param_count, expected_len;
7280 int i;
7281
7282 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007283 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7284 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007285
7286 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007287 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007288 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
7289 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02007290 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03007292 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007293
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05007294 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007295 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007296 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
7297 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02007298 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
7299 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007300 }
7301
Marcel Holtmann181d6952020-05-06 09:57:47 +02007302 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007303
7304 hci_dev_lock(hdev);
7305
7306 hci_conn_params_clear_disabled(hdev);
7307
7308 for (i = 0; i < param_count; i++) {
7309 struct mgmt_conn_param *param = &cp->params[i];
7310 struct hci_conn_params *hci_param;
7311 u16 min, max, latency, timeout;
7312 u8 addr_type;
7313
Marcel Holtmann181d6952020-05-06 09:57:47 +02007314 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
7315 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007316
7317 if (param->addr.type == BDADDR_LE_PUBLIC) {
7318 addr_type = ADDR_LE_DEV_PUBLIC;
7319 } else if (param->addr.type == BDADDR_LE_RANDOM) {
7320 addr_type = ADDR_LE_DEV_RANDOM;
7321 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007322 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007323 continue;
7324 }
7325
7326 min = le16_to_cpu(param->min_interval);
7327 max = le16_to_cpu(param->max_interval);
7328 latency = le16_to_cpu(param->latency);
7329 timeout = le16_to_cpu(param->timeout);
7330
Marcel Holtmann181d6952020-05-06 09:57:47 +02007331 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
7332 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007333
7334 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007335 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007336 continue;
7337 }
7338
7339 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
7340 addr_type);
7341 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007342 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007343 continue;
7344 }
7345
7346 hci_param->conn_min_interval = min;
7347 hci_param->conn_max_interval = max;
7348 hci_param->conn_latency = latency;
7349 hci_param->supervision_timeout = timeout;
7350 }
7351
7352 hci_dev_unlock(hdev);
7353
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007354 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
7355 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007356}
7357
Marcel Holtmanndbece372014-07-04 18:11:55 +02007358static int set_external_config(struct sock *sk, struct hci_dev *hdev,
7359 void *data, u16 len)
7360{
7361 struct mgmt_cp_set_external_config *cp = data;
7362 bool changed;
7363 int err;
7364
Marcel Holtmann181d6952020-05-06 09:57:47 +02007365 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007366
7367 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007368 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7369 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007370
7371 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02007372 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7373 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007374
7375 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02007376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7377 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007378
7379 hci_dev_lock(hdev);
7380
7381 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07007382 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007383 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007384 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007385
7386 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
7387 if (err < 0)
7388 goto unlock;
7389
7390 if (!changed)
7391 goto unlock;
7392
Marcel Holtmannf4537c02014-07-04 19:06:23 +02007393 err = new_options(hdev, sk);
7394
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007395 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02007396 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007397
Marcel Holtmann516018a2015-03-13 02:11:04 -07007398 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007399 hci_dev_set_flag(hdev, HCI_CONFIG);
7400 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007401
7402 queue_work(hdev->req_workqueue, &hdev->power_on);
7403 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02007404 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007405 mgmt_index_added(hdev);
7406 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02007407 }
7408
7409unlock:
7410 hci_dev_unlock(hdev);
7411 return err;
7412}
7413
Marcel Holtmann9713c172014-07-06 12:11:15 +02007414static int set_public_address(struct sock *sk, struct hci_dev *hdev,
7415 void *data, u16 len)
7416{
7417 struct mgmt_cp_set_public_address *cp = data;
7418 bool changed;
7419 int err;
7420
Marcel Holtmann181d6952020-05-06 09:57:47 +02007421 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007422
7423 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007424 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7425 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007426
7427 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02007428 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7429 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007430
7431 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02007432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7433 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007434
7435 hci_dev_lock(hdev);
7436
7437 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
7438 bacpy(&hdev->public_addr, &cp->bdaddr);
7439
7440 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
7441 if (err < 0)
7442 goto unlock;
7443
7444 if (!changed)
7445 goto unlock;
7446
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007447 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02007448 err = new_options(hdev, sk);
7449
7450 if (is_configured(hdev)) {
7451 mgmt_index_removed(hdev);
7452
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007453 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007454
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007455 hci_dev_set_flag(hdev, HCI_CONFIG);
7456 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007457
7458 queue_work(hdev->req_workqueue, &hdev->power_on);
7459 }
7460
7461unlock:
7462 hci_dev_unlock(hdev);
7463 return err;
7464}
7465
Brian Gix177e77a2021-10-27 16:58:53 -07007466static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
7467 int err)
Johan Hedberg40f66c02015-04-07 21:52:22 +03007468{
7469 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
7470 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
7471 u8 *h192, *r192, *h256, *r256;
Brian Gix177e77a2021-10-27 16:58:53 -07007472 struct mgmt_pending_cmd *cmd = data;
7473 struct sk_buff *skb = cmd->skb;
7474 u8 status = mgmt_status(err);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007475 u16 eir_len;
Brian Gix177e77a2021-10-27 16:58:53 -07007476
7477 if (!status) {
7478 if (!skb)
7479 status = MGMT_STATUS_FAILED;
7480 else if (IS_ERR(skb))
7481 status = mgmt_status(PTR_ERR(skb));
7482 else
7483 status = mgmt_status(skb->data[0]);
7484 }
Johan Hedberg40f66c02015-04-07 21:52:22 +03007485
Marcel Holtmann181d6952020-05-06 09:57:47 +02007486 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007487
Johan Hedberg40f66c02015-04-07 21:52:22 +03007488 mgmt_cp = cmd->param;
7489
7490 if (status) {
7491 status = mgmt_status(status);
7492 eir_len = 0;
7493
7494 h192 = NULL;
7495 r192 = NULL;
7496 h256 = NULL;
7497 r256 = NULL;
Brian Gix177e77a2021-10-27 16:58:53 -07007498 } else if (!bredr_sc_enabled(hdev)) {
Johan Hedberg40f66c02015-04-07 21:52:22 +03007499 struct hci_rp_read_local_oob_data *rp;
7500
7501 if (skb->len != sizeof(*rp)) {
7502 status = MGMT_STATUS_FAILED;
7503 eir_len = 0;
7504 } else {
7505 status = MGMT_STATUS_SUCCESS;
7506 rp = (void *)skb->data;
7507
7508 eir_len = 5 + 18 + 18;
7509 h192 = rp->hash;
7510 r192 = rp->rand;
7511 h256 = NULL;
7512 r256 = NULL;
7513 }
7514 } else {
7515 struct hci_rp_read_local_oob_ext_data *rp;
7516
7517 if (skb->len != sizeof(*rp)) {
7518 status = MGMT_STATUS_FAILED;
7519 eir_len = 0;
7520 } else {
7521 status = MGMT_STATUS_SUCCESS;
7522 rp = (void *)skb->data;
7523
7524 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
7525 eir_len = 5 + 18 + 18;
7526 h192 = NULL;
7527 r192 = NULL;
7528 } else {
7529 eir_len = 5 + 18 + 18 + 18 + 18;
7530 h192 = rp->hash192;
7531 r192 = rp->rand192;
7532 }
7533
7534 h256 = rp->hash256;
7535 r256 = rp->rand256;
7536 }
7537 }
7538
7539 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
7540 if (!mgmt_rp)
7541 goto done;
7542
Kees Cooka31e5a42021-08-17 21:39:12 -07007543 if (eir_len == 0)
Johan Hedberg40f66c02015-04-07 21:52:22 +03007544 goto send_rsp;
7545
7546 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
7547 hdev->dev_class, 3);
7548
7549 if (h192 && r192) {
7550 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7551 EIR_SSP_HASH_C192, h192, 16);
7552 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7553 EIR_SSP_RAND_R192, r192, 16);
7554 }
7555
7556 if (h256 && r256) {
7557 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7558 EIR_SSP_HASH_C256, h256, 16);
7559 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7560 EIR_SSP_RAND_R256, r256, 16);
7561 }
7562
7563send_rsp:
7564 mgmt_rp->type = mgmt_cp->type;
7565 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7566
7567 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7568 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7569 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7570 if (err < 0 || status)
7571 goto done;
7572
7573 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7574
7575 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7576 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7577 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7578done:
Brian Gix177e77a2021-10-27 16:58:53 -07007579 if (skb && !IS_ERR(skb))
7580 kfree_skb(skb);
7581
Johan Hedberg40f66c02015-04-07 21:52:22 +03007582 kfree(mgmt_rp);
7583 mgmt_pending_remove(cmd);
7584}
7585
7586static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7587 struct mgmt_cp_read_local_oob_ext_data *cp)
7588{
7589 struct mgmt_pending_cmd *cmd;
Johan Hedberg40f66c02015-04-07 21:52:22 +03007590 int err;
7591
7592 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7593 cp, sizeof(*cp));
7594 if (!cmd)
7595 return -ENOMEM;
7596
Brian Gix177e77a2021-10-27 16:58:53 -07007597 err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
7598 read_local_oob_ext_data_complete);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007599
Johan Hedberg40f66c02015-04-07 21:52:22 +03007600 if (err < 0) {
7601 mgmt_pending_remove(cmd);
7602 return err;
7603 }
7604
7605 return 0;
7606}
7607
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007608static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7609 void *data, u16 data_len)
7610{
7611 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7612 struct mgmt_rp_read_local_oob_ext_data *rp;
7613 size_t rp_len;
7614 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007615 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007616 int err;
7617
Marcel Holtmann181d6952020-05-06 09:57:47 +02007618 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007619
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007620 if (hdev_is_powered(hdev)) {
7621 switch (cp->type) {
7622 case BIT(BDADDR_BREDR):
7623 status = mgmt_bredr_support(hdev);
7624 if (status)
7625 eir_len = 0;
7626 else
7627 eir_len = 5;
7628 break;
7629 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7630 status = mgmt_le_support(hdev);
7631 if (status)
7632 eir_len = 0;
7633 else
7634 eir_len = 9 + 3 + 18 + 18 + 3;
7635 break;
7636 default:
7637 status = MGMT_STATUS_INVALID_PARAMS;
7638 eir_len = 0;
7639 break;
7640 }
7641 } else {
7642 status = MGMT_STATUS_NOT_POWERED;
7643 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007644 }
7645
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007646 rp_len = sizeof(*rp) + eir_len;
7647 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007648 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007649 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007650
Brian Gix81218cb2021-08-23 14:57:29 -07007651 if (!status && !lmp_ssp_capable(hdev)) {
7652 status = MGMT_STATUS_NOT_SUPPORTED;
7653 eir_len = 0;
7654 }
7655
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007656 if (status)
7657 goto complete;
7658
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007659 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007660
7661 eir_len = 0;
7662 switch (cp->type) {
7663 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007664 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7665 err = read_local_ssp_oob_req(hdev, sk, cp);
7666 hci_dev_unlock(hdev);
7667 if (!err)
7668 goto done;
7669
7670 status = MGMT_STATUS_FAILED;
7671 goto complete;
7672 } else {
7673 eir_len = eir_append_data(rp->eir, eir_len,
7674 EIR_CLASS_OF_DEV,
7675 hdev->dev_class, 3);
7676 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007677 break;
7678 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007679 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7680 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007681 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007682 status = MGMT_STATUS_FAILED;
7683 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007684 }
7685
Marcel Holtmanne2135682015-04-02 12:00:58 -07007686 /* This should return the active RPA, but since the RPA
7687 * is only programmed on demand, it is really hard to fill
7688 * this in at the moment. For now disallow retrieving
7689 * local out-of-band data when privacy is in use.
7690 *
7691 * Returning the identity address will not help here since
7692 * pairing happens before the identity resolving key is
7693 * known and thus the connection establishment happens
7694 * based on the RPA and not the identity address.
7695 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007696 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007697 hci_dev_unlock(hdev);
7698 status = MGMT_STATUS_REJECTED;
7699 goto complete;
7700 }
7701
7702 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7703 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7704 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7705 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007706 memcpy(addr, &hdev->static_addr, 6);
7707 addr[6] = 0x01;
7708 } else {
7709 memcpy(addr, &hdev->bdaddr, 6);
7710 addr[6] = 0x00;
7711 }
7712
7713 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7714 addr, sizeof(addr));
7715
7716 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7717 role = 0x02;
7718 else
7719 role = 0x01;
7720
7721 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7722 &role, sizeof(role));
7723
Marcel Holtmann5082a592015-03-16 12:39:00 -07007724 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7725 eir_len = eir_append_data(rp->eir, eir_len,
7726 EIR_LE_SC_CONFIRM,
7727 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007728
Marcel Holtmann5082a592015-03-16 12:39:00 -07007729 eir_len = eir_append_data(rp->eir, eir_len,
7730 EIR_LE_SC_RANDOM,
7731 rand, sizeof(rand));
7732 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007733
Johan Hedbergf2252572015-11-18 12:49:20 +02007734 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007735
7736 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7737 flags |= LE_AD_NO_BREDR;
7738
7739 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7740 &flags, sizeof(flags));
7741 break;
7742 }
7743
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007744 hci_dev_unlock(hdev);
7745
Marcel Holtmann72000df2015-03-16 16:11:21 -07007746 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7747
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007748 status = MGMT_STATUS_SUCCESS;
7749
7750complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007751 rp->type = cp->type;
7752 rp->eir_len = cpu_to_le16(eir_len);
7753
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007754 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007755 status, rp, sizeof(*rp) + eir_len);
7756 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007757 goto done;
7758
7759 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7760 rp, sizeof(*rp) + eir_len,
7761 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007762
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007763done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007764 kfree(rp);
7765
7766 return err;
7767}
7768
Arman Uguray089fa8c2015-03-25 18:53:45 -07007769static u32 get_supported_adv_flags(struct hci_dev *hdev)
7770{
7771 u32 flags = 0;
7772
7773 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7774 flags |= MGMT_ADV_FLAG_DISCOV;
7775 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7776 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007777 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007778 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Daniel Winkler12410572020-12-03 12:12:49 -08007779 flags |= MGMT_ADV_PARAM_DURATION;
7780 flags |= MGMT_ADV_PARAM_TIMEOUT;
7781 flags |= MGMT_ADV_PARAM_INTERVALS;
7782 flags |= MGMT_ADV_PARAM_TX_POWER;
Daniel Winklerff02db12021-03-03 11:15:23 -08007783 flags |= MGMT_ADV_PARAM_SCAN_RSP;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007784
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307785 /* In extended adv TX_POWER returned from Set Adv Param
7786 * will be always valid.
7787 */
7788 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7789 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007790 flags |= MGMT_ADV_FLAG_TX_POWER;
7791
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307792 if (ext_adv_capable(hdev)) {
7793 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007794 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7795 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307796
7797 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7798 flags |= MGMT_ADV_FLAG_SEC_2M;
7799
7800 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7801 flags |= MGMT_ADV_FLAG_SEC_CODED;
7802 }
7803
Arman Uguray089fa8c2015-03-25 18:53:45 -07007804 return flags;
7805}
7806
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007807static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7808 void *data, u16 data_len)
7809{
7810 struct mgmt_rp_read_adv_features *rp;
7811 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007812 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007813 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007814 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007815 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007816
Marcel Holtmann181d6952020-05-06 09:57:47 +02007817 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007818
Arman Uguray089fa8c2015-03-25 18:53:45 -07007819 if (!lmp_le_capable(hdev))
7820 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7821 MGMT_STATUS_REJECTED);
7822
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007823 hci_dev_lock(hdev);
7824
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007825 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007826 rp = kmalloc(rp_len, GFP_ATOMIC);
7827 if (!rp) {
7828 hci_dev_unlock(hdev);
7829 return -ENOMEM;
7830 }
7831
Arman Uguray089fa8c2015-03-25 18:53:45 -07007832 supported_flags = get_supported_adv_flags(hdev);
7833
7834 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007835 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7836 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007837 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007838 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007839
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007840 instance = rp->instance;
7841 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7842 *instance = adv_instance->instance;
7843 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007844 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007845
7846 hci_dev_unlock(hdev);
7847
7848 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7849 MGMT_STATUS_SUCCESS, rp, rp_len);
7850
7851 kfree(rp);
7852
7853 return err;
7854}
7855
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007856static u8 calculate_name_len(struct hci_dev *hdev)
7857{
7858 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7859
Luiz Augusto von Dentz01ce70b2021-09-20 15:59:37 -07007860 return eir_append_local_name(hdev, buf, 0);
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007861}
7862
7863static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7864 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007865{
Arman Uguray4117ed72015-03-23 15:57:14 -07007866 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007867
Marcel Holtmann31a32482015-11-19 16:16:42 +01007868 if (is_adv_data) {
7869 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7870 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007871 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007872 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007873
Szymon Janc2bb368702016-09-18 12:50:05 +02007874 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007875 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007876 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007877 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007878 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007879
Szymon Janc2bb368702016-09-18 12:50:05 +02007880 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007881 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007882 }
7883
Szymon Janc2bb368702016-09-18 12:50:05 +02007884 return max_len;
7885}
7886
7887static bool flags_managed(u32 adv_flags)
7888{
7889 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7890 MGMT_ADV_FLAG_LIMITED_DISCOV |
7891 MGMT_ADV_FLAG_MANAGED_FLAGS);
7892}
7893
7894static bool tx_power_managed(u32 adv_flags)
7895{
7896 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7897}
7898
7899static bool name_managed(u32 adv_flags)
7900{
7901 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7902}
7903
7904static bool appearance_managed(u32 adv_flags)
7905{
7906 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7907}
7908
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007909static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7910 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007911{
7912 int i, cur_len;
7913 u8 max_len;
7914
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007915 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007916
Arman Uguray4117ed72015-03-23 15:57:14 -07007917 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007918 return false;
7919
Arman Uguray4117ed72015-03-23 15:57:14 -07007920 /* Make sure that the data is correctly formatted. */
7921 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7922 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007923
Luiz Augusto von Dentz799acb92021-05-28 11:45:02 -07007924 if (!cur_len)
7925 continue;
7926
Szymon Janc9c9db782016-09-18 12:50:06 +02007927 if (data[i + 1] == EIR_FLAGS &&
7928 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007929 return false;
7930
Szymon Janc2bb368702016-09-18 12:50:05 +02007931 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7932 return false;
7933
7934 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7935 return false;
7936
7937 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7938 return false;
7939
7940 if (data[i + 1] == EIR_APPEARANCE &&
7941 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007942 return false;
7943
Arman Uguray24b4f382015-03-23 15:57:12 -07007944 /* If the current field length would exceed the total data
7945 * length, then it's invalid.
7946 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007947 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007948 return false;
7949 }
7950
7951 return true;
7952}
7953
Daniel Winkler12410572020-12-03 12:12:49 -08007954static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
7955{
7956 u32 supported_flags, phy_flags;
7957
7958 /* The current implementation only supports a subset of the specified
7959 * flags. Also need to check mutual exclusiveness of sec flags.
7960 */
7961 supported_flags = get_supported_adv_flags(hdev);
7962 phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK;
7963 if (adv_flags & ~supported_flags ||
7964 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
7965 return false;
7966
7967 return true;
7968}
7969
7970static bool adv_busy(struct hci_dev *hdev)
7971{
7972 return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7973 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7974 pending_find(MGMT_OP_SET_LE, hdev) ||
7975 pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
7976 pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
7977}
7978
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007979static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
7980 int err)
Arman Uguray24b4f382015-03-23 15:57:12 -07007981{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007982 struct adv_info *adv, *n;
Arman Uguray24b4f382015-03-23 15:57:12 -07007983
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007984 bt_dev_dbg(hdev, "err %d", err);
Arman Uguray24b4f382015-03-23 15:57:12 -07007985
7986 hci_dev_lock(hdev);
7987
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007988 list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
7989 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007990
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007991 if (!adv->pending)
Florian Grandelfffd38b2015-06-18 03:16:47 +02007992 continue;
7993
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007994 if (!err) {
7995 adv->pending = false;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007996 continue;
7997 }
7998
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07007999 instance = adv->instance;
Florian Grandelfffd38b2015-06-18 03:16:47 +02008000
8001 if (hdev->cur_adv_instance == instance)
8002 cancel_adv_timeout(hdev);
8003
8004 hci_remove_adv_instance(hdev, instance);
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008005 mgmt_advertising_removed(sk, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07008006 }
8007
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008008 hci_dev_unlock(hdev);
8009}
Arman Uguray24b4f382015-03-23 15:57:12 -07008010
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008011static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
8012{
8013 struct mgmt_pending_cmd *cmd = data;
8014 struct mgmt_cp_add_advertising *cp = cmd->param;
8015 struct mgmt_rp_add_advertising rp;
8016
8017 memset(&rp, 0, sizeof(rp));
8018
Florian Grandelfffd38b2015-06-18 03:16:47 +02008019 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008020
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008021 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07008022 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008023 mgmt_status(err));
Arman Uguray24b4f382015-03-23 15:57:12 -07008024 else
8025 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008026 mgmt_status(err), &rp, sizeof(rp));
Arman Uguray24b4f382015-03-23 15:57:12 -07008027
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008028 add_adv_complete(hdev, cmd->sk, cp->instance, err);
Arman Uguray24b4f382015-03-23 15:57:12 -07008029
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008030 mgmt_pending_free(cmd);
8031}
8032
8033static int add_advertising_sync(struct hci_dev *hdev, void *data)
8034{
8035 struct mgmt_pending_cmd *cmd = data;
8036 struct mgmt_cp_add_advertising *cp = cmd->param;
8037
8038 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07008039}
8040
8041static int add_advertising(struct sock *sk, struct hci_dev *hdev,
8042 void *data, u16 data_len)
8043{
8044 struct mgmt_cp_add_advertising *cp = data;
8045 struct mgmt_rp_add_advertising rp;
8046 u32 flags;
8047 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02008048 u16 timeout, duration;
8049 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
8050 u8 schedule_instance = 0;
8051 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008052 int err;
8053 struct mgmt_pending_cmd *cmd;
Arman Uguray24b4f382015-03-23 15:57:12 -07008054
Marcel Holtmann181d6952020-05-06 09:57:47 +02008055 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07008056
8057 status = mgmt_le_support(hdev);
8058 if (status)
8059 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8060 status);
8061
Daniel Winkler87597482020-08-25 16:31:50 -07008062 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01008063 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8064 MGMT_STATUS_INVALID_PARAMS);
8065
Johan Hedberg6a0e7802016-03-11 09:56:33 +02008066 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
8067 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8068 MGMT_STATUS_INVALID_PARAMS);
8069
Arman Uguray24b4f382015-03-23 15:57:12 -07008070 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07008071 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008072 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07008073
Daniel Winkler12410572020-12-03 12:12:49 -08008074 if (!requested_adv_flags_are_valid(hdev, flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07008075 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8076 MGMT_STATUS_INVALID_PARAMS);
8077
8078 hci_dev_lock(hdev);
8079
Arman Uguray912098a2015-03-23 15:57:15 -07008080 if (timeout && !hdev_is_powered(hdev)) {
8081 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8082 MGMT_STATUS_REJECTED);
8083 goto unlock;
8084 }
8085
Daniel Winkler12410572020-12-03 12:12:49 -08008086 if (adv_busy(hdev)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008087 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8088 MGMT_STATUS_BUSY);
8089 goto unlock;
8090 }
8091
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008092 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
8093 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07008094 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07008095 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8096 MGMT_STATUS_INVALID_PARAMS);
8097 goto unlock;
8098 }
8099
Florian Grandelfffd38b2015-06-18 03:16:47 +02008100 err = hci_add_adv_instance(hdev, cp->instance, flags,
8101 cp->adv_data_len, cp->data,
8102 cp->scan_rsp_len,
8103 cp->data + cp->adv_data_len,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008104 timeout, duration,
8105 HCI_ADV_TX_POWER_NO_PREFERENCE,
8106 hdev->le_adv_min_interval,
8107 hdev->le_adv_max_interval);
Florian Grandelfffd38b2015-06-18 03:16:47 +02008108 if (err < 0) {
8109 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8110 MGMT_STATUS_FAILED);
8111 goto unlock;
8112 }
Arman Uguray24b4f382015-03-23 15:57:12 -07008113
Florian Grandelfffd38b2015-06-18 03:16:47 +02008114 /* Only trigger an advertising added event if a new instance was
8115 * actually added.
8116 */
8117 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02008118 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07008119
Florian Grandelfffd38b2015-06-18 03:16:47 +02008120 if (hdev->cur_adv_instance == cp->instance) {
8121 /* If the currently advertised instance is being changed then
8122 * cancel the current advertising and schedule the next
8123 * instance. If there is only one instance then the overridden
8124 * advertising data will be visible right away.
8125 */
8126 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07008127
Florian Grandelfffd38b2015-06-18 03:16:47 +02008128 next_instance = hci_get_next_instance(hdev, cp->instance);
8129 if (next_instance)
8130 schedule_instance = next_instance->instance;
8131 } else if (!hdev->adv_instance_timeout) {
8132 /* Immediately advertise the new instance if no other
8133 * instance is currently being advertised.
8134 */
8135 schedule_instance = cp->instance;
8136 }
Arman Uguray912098a2015-03-23 15:57:15 -07008137
Florian Grandelfffd38b2015-06-18 03:16:47 +02008138 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
8139 * there is no instance to be advertised then we have no HCI
8140 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07008141 */
8142 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02008143 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
8144 !schedule_instance) {
8145 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008146 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8147 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8148 goto unlock;
8149 }
8150
8151 /* We're good to go, update advertising data, parameters, and start
8152 * advertising.
8153 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008154 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
Arman Uguray24b4f382015-03-23 15:57:12 -07008155 data_len);
8156 if (!cmd) {
8157 err = -ENOMEM;
8158 goto unlock;
8159 }
8160
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008161 cp->instance = schedule_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07008162
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008163 err = hci_cmd_sync_queue(hdev, add_advertising_sync, cmd,
8164 add_advertising_complete);
8165 if (err < 0)
8166 mgmt_pending_free(cmd);
Arman Uguray24b4f382015-03-23 15:57:12 -07008167
8168unlock:
8169 hci_dev_unlock(hdev);
8170
8171 return err;
8172}
8173
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008174static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
8175 int err)
Daniel Winkler12410572020-12-03 12:12:49 -08008176{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008177 struct mgmt_pending_cmd *cmd = data;
8178 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
Daniel Winkler12410572020-12-03 12:12:49 -08008179 struct mgmt_rp_add_ext_adv_params rp;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008180 struct adv_info *adv;
Daniel Winkler12410572020-12-03 12:12:49 -08008181 u32 flags;
8182
8183 BT_DBG("%s", hdev->name);
8184
8185 hci_dev_lock(hdev);
8186
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008187 adv = hci_find_adv_instance(hdev, cp->instance);
8188 if (!adv)
Daniel Winkler12410572020-12-03 12:12:49 -08008189 goto unlock;
8190
8191 rp.instance = cp->instance;
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008192 rp.tx_power = adv->tx_power;
Daniel Winkler12410572020-12-03 12:12:49 -08008193
8194 /* While we're at it, inform userspace of the available space for this
8195 * advertisement, given the flags that will be used.
8196 */
8197 flags = __le32_to_cpu(cp->flags);
8198 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8199 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8200
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008201 if (err) {
Daniel Winkler12410572020-12-03 12:12:49 -08008202 /* If this advertisement was previously advertising and we
8203 * failed to update it, we signal that it has been removed and
8204 * delete its structure
8205 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008206 if (!adv->pending)
Daniel Winkler12410572020-12-03 12:12:49 -08008207 mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
8208
8209 hci_remove_adv_instance(hdev, cp->instance);
8210
8211 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008212 mgmt_status(err));
Daniel Winkler12410572020-12-03 12:12:49 -08008213 } else {
8214 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008215 mgmt_status(err), &rp, sizeof(rp));
Daniel Winkler12410572020-12-03 12:12:49 -08008216 }
8217
8218unlock:
8219 if (cmd)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008220 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008221
8222 hci_dev_unlock(hdev);
8223}
8224
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008225static int add_ext_adv_params_sync(struct hci_dev *hdev, void *data)
8226{
8227 struct mgmt_pending_cmd *cmd = data;
8228 struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
8229
8230 return hci_setup_ext_adv_instance_sync(hdev, cp->instance);
8231}
8232
Daniel Winkler12410572020-12-03 12:12:49 -08008233static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
8234 void *data, u16 data_len)
8235{
8236 struct mgmt_cp_add_ext_adv_params *cp = data;
8237 struct mgmt_rp_add_ext_adv_params rp;
8238 struct mgmt_pending_cmd *cmd = NULL;
Daniel Winkler12410572020-12-03 12:12:49 -08008239 u32 flags, min_interval, max_interval;
8240 u16 timeout, duration;
8241 u8 status;
8242 s8 tx_power;
8243 int err;
8244
8245 BT_DBG("%s", hdev->name);
8246
8247 status = mgmt_le_support(hdev);
8248 if (status)
8249 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8250 status);
8251
8252 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
8253 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8254 MGMT_STATUS_INVALID_PARAMS);
8255
8256 /* The purpose of breaking add_advertising into two separate MGMT calls
8257 * for params and data is to allow more parameters to be added to this
8258 * structure in the future. For this reason, we verify that we have the
8259 * bare minimum structure we know of when the interface was defined. Any
8260 * extra parameters we don't know about will be ignored in this request.
8261 */
8262 if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE)
8263 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
8264 MGMT_STATUS_INVALID_PARAMS);
8265
8266 flags = __le32_to_cpu(cp->flags);
8267
8268 if (!requested_adv_flags_are_valid(hdev, flags))
8269 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8270 MGMT_STATUS_INVALID_PARAMS);
8271
8272 hci_dev_lock(hdev);
8273
8274 /* In new interface, we require that we are powered to register */
8275 if (!hdev_is_powered(hdev)) {
8276 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8277 MGMT_STATUS_REJECTED);
8278 goto unlock;
8279 }
8280
8281 if (adv_busy(hdev)) {
8282 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8283 MGMT_STATUS_BUSY);
8284 goto unlock;
8285 }
8286
8287 /* Parse defined parameters from request, use defaults otherwise */
8288 timeout = (flags & MGMT_ADV_PARAM_TIMEOUT) ?
8289 __le16_to_cpu(cp->timeout) : 0;
8290
8291 duration = (flags & MGMT_ADV_PARAM_DURATION) ?
8292 __le16_to_cpu(cp->duration) :
8293 hdev->def_multi_adv_rotation_duration;
8294
8295 min_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8296 __le32_to_cpu(cp->min_interval) :
8297 hdev->le_adv_min_interval;
8298
8299 max_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
8300 __le32_to_cpu(cp->max_interval) :
8301 hdev->le_adv_max_interval;
8302
8303 tx_power = (flags & MGMT_ADV_PARAM_TX_POWER) ?
8304 cp->tx_power :
8305 HCI_ADV_TX_POWER_NO_PREFERENCE;
8306
8307 /* Create advertising instance with no advertising or response data */
8308 err = hci_add_adv_instance(hdev, cp->instance, flags,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08008309 0, NULL, 0, NULL, timeout, duration,
8310 tx_power, min_interval, max_interval);
Daniel Winkler12410572020-12-03 12:12:49 -08008311
8312 if (err < 0) {
8313 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
8314 MGMT_STATUS_FAILED);
8315 goto unlock;
8316 }
8317
Daniel Winkler12410572020-12-03 12:12:49 -08008318 /* Submit request for advertising params if ext adv available */
8319 if (ext_adv_capable(hdev)) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008320 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev,
8321 data, data_len);
Daniel Winkler12410572020-12-03 12:12:49 -08008322 if (!cmd) {
8323 err = -ENOMEM;
8324 hci_remove_adv_instance(hdev, cp->instance);
8325 goto unlock;
8326 }
8327
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008328 err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd,
8329 add_ext_adv_params_complete);
8330 if (err < 0)
8331 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008332 } else {
8333 rp.instance = cp->instance;
8334 rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
8335 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8336 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8337 err = mgmt_cmd_complete(sk, hdev->id,
8338 MGMT_OP_ADD_EXT_ADV_PARAMS,
8339 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8340 }
8341
8342unlock:
8343 hci_dev_unlock(hdev);
8344
8345 return err;
8346}
8347
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008348static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
8349{
8350 struct mgmt_pending_cmd *cmd = data;
8351 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8352 struct mgmt_rp_add_advertising rp;
8353
8354 add_adv_complete(hdev, cmd->sk, cp->instance, err);
8355
8356 memset(&rp, 0, sizeof(rp));
8357
8358 rp.instance = cp->instance;
8359
8360 if (err)
8361 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8362 mgmt_status(err));
8363 else
8364 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8365 mgmt_status(err), &rp, sizeof(rp));
8366
8367 mgmt_pending_free(cmd);
8368}
8369
8370static int add_ext_adv_data_sync(struct hci_dev *hdev, void *data)
8371{
8372 struct mgmt_pending_cmd *cmd = data;
8373 struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
8374 int err;
8375
8376 if (ext_adv_capable(hdev)) {
8377 err = hci_update_adv_data_sync(hdev, cp->instance);
8378 if (err)
8379 return err;
8380
8381 err = hci_update_scan_rsp_data_sync(hdev, cp->instance);
8382 if (err)
8383 return err;
8384
8385 return hci_enable_ext_advertising_sync(hdev, cp->instance);
8386 }
8387
8388 return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
8389}
8390
Daniel Winkler12410572020-12-03 12:12:49 -08008391static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
8392 u16 data_len)
8393{
8394 struct mgmt_cp_add_ext_adv_data *cp = data;
8395 struct mgmt_rp_add_ext_adv_data rp;
8396 u8 schedule_instance = 0;
8397 struct adv_info *next_instance;
8398 struct adv_info *adv_instance;
8399 int err = 0;
8400 struct mgmt_pending_cmd *cmd;
Daniel Winkler12410572020-12-03 12:12:49 -08008401
8402 BT_DBG("%s", hdev->name);
8403
8404 hci_dev_lock(hdev);
8405
8406 adv_instance = hci_find_adv_instance(hdev, cp->instance);
8407
8408 if (!adv_instance) {
8409 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8410 MGMT_STATUS_INVALID_PARAMS);
8411 goto unlock;
8412 }
8413
8414 /* In new interface, we require that we are powered to register */
8415 if (!hdev_is_powered(hdev)) {
8416 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8417 MGMT_STATUS_REJECTED);
8418 goto clear_new_instance;
8419 }
8420
8421 if (adv_busy(hdev)) {
8422 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8423 MGMT_STATUS_BUSY);
8424 goto clear_new_instance;
8425 }
8426
8427 /* Validate new data */
8428 if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data,
8429 cp->adv_data_len, true) ||
8430 !tlv_data_is_valid(hdev, adv_instance->flags, cp->data +
8431 cp->adv_data_len, cp->scan_rsp_len, false)) {
8432 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8433 MGMT_STATUS_INVALID_PARAMS);
8434 goto clear_new_instance;
8435 }
8436
8437 /* Set the data in the advertising instance */
8438 hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len,
8439 cp->data, cp->scan_rsp_len,
8440 cp->data + cp->adv_data_len);
8441
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008442 /* If using software rotation, determine next instance to use */
8443 if (hdev->cur_adv_instance == cp->instance) {
8444 /* If the currently advertised instance is being changed
8445 * then cancel the current advertising and schedule the
8446 * next instance. If there is only one instance then the
8447 * overridden advertising data will be visible right
8448 * away
Daniel Winkler12410572020-12-03 12:12:49 -08008449 */
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008450 cancel_adv_timeout(hdev);
Daniel Winkler12410572020-12-03 12:12:49 -08008451
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008452 next_instance = hci_get_next_instance(hdev, cp->instance);
8453 if (next_instance)
8454 schedule_instance = next_instance->instance;
8455 } else if (!hdev->adv_instance_timeout) {
8456 /* Immediately advertise the new instance if no other
8457 * instance is currently being advertised.
8458 */
8459 schedule_instance = cp->instance;
Daniel Winkler12410572020-12-03 12:12:49 -08008460 }
8461
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008462 /* If the HCI_ADVERTISING flag is set or there is no instance to
8463 * be advertised then we have no HCI communication to make.
8464 * Simply return.
8465 */
8466 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) {
8467 if (adv_instance->pending) {
8468 mgmt_advertising_added(sk, hdev, cp->instance);
8469 adv_instance->pending = false;
8470 }
8471 rp.instance = cp->instance;
8472 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8473 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8474 goto unlock;
8475 }
8476
8477 cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
Daniel Winkler12410572020-12-03 12:12:49 -08008478 data_len);
8479 if (!cmd) {
8480 err = -ENOMEM;
8481 goto clear_new_instance;
8482 }
8483
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008484 err = hci_cmd_sync_queue(hdev, add_ext_adv_data_sync, cmd,
8485 add_ext_adv_data_complete);
Daniel Winkler12410572020-12-03 12:12:49 -08008486 if (err < 0) {
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008487 mgmt_pending_free(cmd);
Daniel Winkler12410572020-12-03 12:12:49 -08008488 goto clear_new_instance;
8489 }
8490
8491 /* We were successful in updating data, so trigger advertising_added
8492 * event if this is an instance that wasn't previously advertising. If
8493 * a failure occurs in the requests we initiated, we will remove the
8494 * instance again in add_advertising_complete
8495 */
8496 if (adv_instance->pending)
8497 mgmt_advertising_added(sk, hdev, cp->instance);
8498
8499 goto unlock;
8500
8501clear_new_instance:
8502 hci_remove_adv_instance(hdev, cp->instance);
8503
8504unlock:
8505 hci_dev_unlock(hdev);
8506
8507 return err;
8508}
8509
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008510static void remove_advertising_complete(struct hci_dev *hdev, void *data,
8511 int err)
Arman Ugurayda9293352015-03-23 15:57:13 -07008512{
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008513 struct mgmt_pending_cmd *cmd = data;
8514 struct mgmt_cp_remove_advertising *cp = cmd->param;
Arman Ugurayda9293352015-03-23 15:57:13 -07008515 struct mgmt_rp_remove_advertising rp;
8516
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008517 bt_dev_dbg(hdev, "err %d", err);
Arman Ugurayda9293352015-03-23 15:57:13 -07008518
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008519 memset(&rp, 0, sizeof(rp));
Florian Grandel01948332015-06-18 03:16:48 +02008520 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008521
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008522 if (err)
8523 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
8524 mgmt_status(err));
8525 else
8526 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
8527 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Arman Ugurayda9293352015-03-23 15:57:13 -07008528
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008529 mgmt_pending_free(cmd);
8530}
8531
8532static int remove_advertising_sync(struct hci_dev *hdev, void *data)
8533{
8534 struct mgmt_pending_cmd *cmd = data;
8535 struct mgmt_cp_remove_advertising *cp = cmd->param;
8536 int err;
8537
8538 err = hci_remove_advertising_sync(hdev, cmd->sk, cp->instance, true);
8539 if (err)
8540 return err;
8541
8542 if (list_empty(&hdev->adv_instances))
8543 err = hci_disable_advertising_sync(hdev);
8544
8545 return err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008546}
8547
8548static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
8549 void *data, u16 data_len)
8550{
8551 struct mgmt_cp_remove_advertising *cp = data;
Arman Ugurayda9293352015-03-23 15:57:13 -07008552 struct mgmt_pending_cmd *cmd;
Johan Hedberg952497b2015-06-18 21:05:31 +03008553 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008554
Marcel Holtmann181d6952020-05-06 09:57:47 +02008555 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07008556
Arman Ugurayda9293352015-03-23 15:57:13 -07008557 hci_dev_lock(hdev);
8558
Johan Hedberg952497b2015-06-18 21:05:31 +03008559 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02008560 err = mgmt_cmd_status(sk, hdev->id,
8561 MGMT_OP_REMOVE_ADVERTISING,
8562 MGMT_STATUS_INVALID_PARAMS);
8563 goto unlock;
8564 }
8565
Arman Ugurayda9293352015-03-23 15:57:13 -07008566 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
8567 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
8568 pending_find(MGMT_OP_SET_LE, hdev)) {
8569 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8570 MGMT_STATUS_BUSY);
8571 goto unlock;
8572 }
8573
Johan Hedberg17fd08f2015-11-26 12:15:59 +02008574 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07008575 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8576 MGMT_STATUS_INVALID_PARAMS);
8577 goto unlock;
8578 }
8579
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008580 cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
Arman Ugurayda9293352015-03-23 15:57:13 -07008581 data_len);
8582 if (!cmd) {
8583 err = -ENOMEM;
8584 goto unlock;
8585 }
8586
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008587 err = hci_cmd_sync_queue(hdev, remove_advertising_sync, cmd,
8588 remove_advertising_complete);
Arman Ugurayda9293352015-03-23 15:57:13 -07008589 if (err < 0)
Luiz Augusto von Dentzcba6b752021-10-27 16:58:40 -07008590 mgmt_pending_free(cmd);
Arman Ugurayda9293352015-03-23 15:57:13 -07008591
8592unlock:
8593 hci_dev_unlock(hdev);
8594
8595 return err;
8596}
8597
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008598static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
8599 void *data, u16 data_len)
8600{
8601 struct mgmt_cp_get_adv_size_info *cp = data;
8602 struct mgmt_rp_get_adv_size_info rp;
8603 u32 flags, supported_flags;
8604 int err;
8605
Marcel Holtmann181d6952020-05-06 09:57:47 +02008606 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008607
8608 if (!lmp_le_capable(hdev))
8609 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8610 MGMT_STATUS_REJECTED);
8611
Daniel Winkler87597482020-08-25 16:31:50 -07008612 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008613 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8614 MGMT_STATUS_INVALID_PARAMS);
8615
8616 flags = __le32_to_cpu(cp->flags);
8617
8618 /* The current implementation only supports a subset of the specified
8619 * flags.
8620 */
8621 supported_flags = get_supported_adv_flags(hdev);
8622 if (flags & ~supported_flags)
8623 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8624 MGMT_STATUS_INVALID_PARAMS);
8625
8626 rp.instance = cp->instance;
8627 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008628 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8629 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008630
8631 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8632 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8633
8634 return err;
8635}
8636
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008637static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008638 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008639 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008640 HCI_MGMT_NO_HDEV |
8641 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008642 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008643 HCI_MGMT_NO_HDEV |
8644 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008645 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008646 HCI_MGMT_NO_HDEV |
8647 HCI_MGMT_UNTRUSTED },
8648 { read_controller_info, MGMT_READ_INFO_SIZE,
8649 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008650 { set_powered, MGMT_SETTING_SIZE },
8651 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
8652 { set_connectable, MGMT_SETTING_SIZE },
8653 { set_fast_connectable, MGMT_SETTING_SIZE },
8654 { set_bondable, MGMT_SETTING_SIZE },
8655 { set_link_security, MGMT_SETTING_SIZE },
8656 { set_ssp, MGMT_SETTING_SIZE },
8657 { set_hs, MGMT_SETTING_SIZE },
8658 { set_le, MGMT_SETTING_SIZE },
8659 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
8660 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
8661 { add_uuid, MGMT_ADD_UUID_SIZE },
8662 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008663 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
8664 HCI_MGMT_VAR_LEN },
8665 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
8666 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008667 { disconnect, MGMT_DISCONNECT_SIZE },
8668 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
8669 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
8670 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
8671 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
8672 { pair_device, MGMT_PAIR_DEVICE_SIZE },
8673 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
8674 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
8675 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
8676 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
8677 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
8678 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008679 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
8680 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
8681 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008682 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
8683 { start_discovery, MGMT_START_DISCOVERY_SIZE },
8684 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
8685 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
8686 { block_device, MGMT_BLOCK_DEVICE_SIZE },
8687 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
8688 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
8689 { set_advertising, MGMT_SETTING_SIZE },
8690 { set_bredr, MGMT_SETTING_SIZE },
8691 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
8692 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
8693 { set_secure_conn, MGMT_SETTING_SIZE },
8694 { set_debug_keys, MGMT_SETTING_SIZE },
8695 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008696 { load_irks, MGMT_LOAD_IRKS_SIZE,
8697 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008698 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
8699 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
8700 { add_device, MGMT_ADD_DEVICE_SIZE },
8701 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008702 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
8703 HCI_MGMT_VAR_LEN },
8704 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008705 HCI_MGMT_NO_HDEV |
8706 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008707 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008708 HCI_MGMT_UNCONFIGURED |
8709 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008710 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
8711 HCI_MGMT_UNCONFIGURED },
8712 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
8713 HCI_MGMT_UNCONFIGURED },
8714 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
8715 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07008716 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07008717 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008718 HCI_MGMT_NO_HDEV |
8719 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07008720 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07008721 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
8722 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07008723 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008724 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02008725 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008726 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
8727 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02008728 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05308729 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05308730 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00008731 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
8732 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00008733 { set_wideband_speech, MGMT_SETTING_SIZE },
Daniel Winkler4d9b9522020-12-03 12:12:52 -08008734 { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02008735 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02008736 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
8737 HCI_MGMT_UNTRUSTED |
8738 HCI_MGMT_HDEV_OPTIONAL },
8739 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
8740 HCI_MGMT_VAR_LEN |
8741 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00008742 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
8743 HCI_MGMT_UNTRUSTED },
8744 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
8745 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02008746 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
8747 HCI_MGMT_UNTRUSTED },
8748 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
8749 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02008750 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
8751 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02008752 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02008753 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
8754 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02008755 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Daniel Winkler12410572020-12-03 12:12:49 -08008756 { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE,
8757 HCI_MGMT_VAR_LEN },
8758 { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
8759 HCI_MGMT_VAR_LEN },
Archie Pusakab4a221e2021-01-22 16:36:11 +08008760 { add_adv_patterns_monitor_rssi,
8761 MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
8762 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008763};
8764
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008765void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008766{
Marcel Holtmannced85542015-03-14 19:27:56 -07008767 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03008768
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008769 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8770 return;
8771
Marcel Holtmannf9207332015-03-14 19:27:55 -07008772 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008773 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008774 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8775 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
8776 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008777 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008778 } else {
8779 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
8780 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008781 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008782 }
8783 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008784 case HCI_AMP:
8785 ev.type = 0x02;
8786 break;
8787 default:
8788 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008789 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008790
8791 ev.bus = hdev->bus;
8792
8793 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
8794 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008795}
8796
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008797void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008798{
Marcel Holtmannced85542015-03-14 19:27:56 -07008799 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02008800 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02008801
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008802 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8803 return;
8804
Marcel Holtmannf9207332015-03-14 19:27:55 -07008805 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008806 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008807 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02008808
Marcel Holtmannf9207332015-03-14 19:27:55 -07008809 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8810 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
8811 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008812 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008813 } else {
8814 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
8815 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008816 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008817 }
8818 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008819 case HCI_AMP:
8820 ev.type = 0x02;
8821 break;
8822 default:
8823 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008824 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008825
8826 ev.bus = hdev->bus;
8827
8828 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
8829 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008830}
8831
Johan Hedberg2ff13892015-11-25 16:15:44 +02008832void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05008833{
8834 struct cmd_lookup match = { NULL, hdev };
8835
Marcel Holtmann181d6952020-05-06 09:57:47 +02008836 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05008837
Johan Hedberg2ff13892015-11-25 16:15:44 +02008838 hci_dev_lock(hdev);
8839
8840 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008841 restart_le_actions(hdev);
Luiz Augusto von Dentzad383c22021-10-27 16:58:42 -07008842 hci_update_passive_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08008843 }
8844
Johan Hedberg229ab392013-03-15 17:06:53 -05008845 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
8846
8847 new_settings(hdev, match.sk);
8848
Johan Hedberg229ab392013-03-15 17:06:53 -05008849 if (match.sk)
8850 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02008851
8852 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05008853}
8854
Johan Hedberg2ff13892015-11-25 16:15:44 +02008855void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02008856{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02008857 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02008858 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02008859
Johan Hedberg229ab392013-03-15 17:06:53 -05008860 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02008861
8862 /* If the power off is because of hdev unregistration let
8863 * use the appropriate INVALID_INDEX status. Otherwise use
8864 * NOT_POWERED. We cover both scenarios here since later in
8865 * mgmt_index_removed() any hci_conn callbacks will have already
8866 * been triggered, potentially causing misleading DISCONNECTED
8867 * status responses.
8868 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008869 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02008870 status = MGMT_STATUS_INVALID_INDEX;
8871 else
8872 status = MGMT_STATUS_NOT_POWERED;
8873
8874 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008875
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008876 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008877 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8878 zero_cod, sizeof(zero_cod),
8879 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008880 ext_info_changed(hdev, NULL);
8881 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008882
Johan Hedberg2ff13892015-11-25 16:15:44 +02008883 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008884
8885 if (match.sk)
8886 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008887}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008888
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008889void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008890{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008891 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008892 u8 status;
8893
Johan Hedberg333ae952015-03-17 13:48:47 +02008894 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008895 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008896 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008897
8898 if (err == -ERFKILL)
8899 status = MGMT_STATUS_RFKILLED;
8900 else
8901 status = MGMT_STATUS_FAILED;
8902
Johan Hedberga69e8372015-03-06 21:08:53 +02008903 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008904
8905 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008906}
8907
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008908void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8909 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008910{
Johan Hedberg86742e12011-11-07 23:13:38 +02008911 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008912
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008913 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008914
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008915 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008916 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008917 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008918 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008919 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008920 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008921
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008922 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008923}
Johan Hedbergf7520542011-01-20 12:34:39 +02008924
Johan Hedbergd7b25452014-05-23 13:19:53 +03008925static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8926{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008927 switch (ltk->type) {
8928 case SMP_LTK:
Archie Pusakafad646e2021-05-31 16:37:25 +08008929 case SMP_LTK_RESPONDER:
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008930 if (ltk->authenticated)
8931 return MGMT_LTK_AUTHENTICATED;
8932 return MGMT_LTK_UNAUTHENTICATED;
8933 case SMP_LTK_P256:
8934 if (ltk->authenticated)
8935 return MGMT_LTK_P256_AUTH;
8936 return MGMT_LTK_P256_UNAUTH;
8937 case SMP_LTK_P256_DEBUG:
8938 return MGMT_LTK_P256_DEBUG;
8939 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008940
8941 return MGMT_LTK_UNAUTHENTICATED;
8942}
8943
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008944void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008945{
8946 struct mgmt_ev_new_long_term_key ev;
8947
8948 memset(&ev, 0, sizeof(ev));
8949
Marcel Holtmann5192d302014-02-19 17:11:58 -08008950 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008951 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008952 * to store long term keys. Their addresses will change the
8953 * next time around.
8954 *
8955 * Only when a remote device provides an identity address
8956 * make sure the long term key is stored. If the remote
8957 * identity is known, the long term keys are internally
8958 * mapped to the identity address. So allow static random
8959 * and public addresses here.
8960 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008961 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8962 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8963 ev.store_hint = 0x00;
8964 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008965 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008966
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008967 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008968 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008969 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008970 ev.key.enc_size = key->enc_size;
8971 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008972 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008973
Johan Hedberg2ceba532014-06-16 19:25:16 +03008974 if (key->type == SMP_LTK)
Archie Pusakafad646e2021-05-31 16:37:25 +08008975 ev.key.initiator = 1;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008976
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008977 /* Make sure we copy only the significant bytes based on the
8978 * encryption key size, and set the rest of the value to zeroes.
8979 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008980 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008981 memset(ev.key.val + key->enc_size, 0,
8982 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008983
Marcel Holtmann083368f2013-10-15 14:26:29 -07008984 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008985}
8986
Johan Hedbergcad20c22015-10-12 13:36:19 +02008987void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008988{
8989 struct mgmt_ev_new_irk ev;
8990
8991 memset(&ev, 0, sizeof(ev));
8992
Johan Hedbergcad20c22015-10-12 13:36:19 +02008993 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008994
Johan Hedberg95fbac82014-02-19 15:18:31 +02008995 bacpy(&ev.rpa, &irk->rpa);
8996 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8997 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8998 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8999
9000 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
9001}
9002
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07009003void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
9004 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07009005{
9006 struct mgmt_ev_new_csrk ev;
9007
9008 memset(&ev, 0, sizeof(ev));
9009
9010 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02009011 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07009012 * to store signature resolving keys. Their addresses will change
9013 * the next time around.
9014 *
9015 * Only when a remote device provides an identity address
9016 * make sure the signature resolving key is stored. So allow
9017 * static random and public addresses here.
9018 */
9019 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
9020 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
9021 ev.store_hint = 0x00;
9022 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07009023 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07009024
9025 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
9026 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02009027 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07009028 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
9029
9030 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
9031}
9032
Andre Guedesffb5a8272014-07-01 18:10:11 -03009033void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03009034 u8 bdaddr_type, u8 store_hint, u16 min_interval,
9035 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03009036{
9037 struct mgmt_ev_new_conn_param ev;
9038
Johan Hedbergc103aea2014-07-02 17:37:34 +03009039 if (!hci_is_identity_address(bdaddr, bdaddr_type))
9040 return;
9041
Andre Guedesffb5a8272014-07-01 18:10:11 -03009042 memset(&ev, 0, sizeof(ev));
9043 bacpy(&ev.addr.bdaddr, bdaddr);
9044 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03009045 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03009046 ev.min_interval = cpu_to_le16(min_interval);
9047 ev.max_interval = cpu_to_le16(max_interval);
9048 ev.latency = cpu_to_le16(latency);
9049 ev.timeout = cpu_to_le16(timeout);
9050
9051 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
9052}
9053
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00009054void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
Yu Liu1c6ed312021-04-09 15:04:06 -07009055 u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02009056{
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009057 struct sk_buff *skb;
9058 struct mgmt_ev_device_connected *ev;
Johan Hedbergb644ba32012-01-17 21:48:47 +02009059 u16 eir_len = 0;
Yu Liu1c6ed312021-04-09 15:04:06 -07009060 u32 flags = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02009061
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009062 if (conn->le_adv_data_len > 0)
9063 skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
9064 conn->le_adv_data_len);
9065 else
9066 skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
9067 2 + name_len + 5);
9068
9069 ev = skb_put(skb, sizeof(*ev));
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00009070 bacpy(&ev->addr.bdaddr, &conn->dst);
9071 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02009072
Yu Liu1c6ed312021-04-09 15:04:06 -07009073 if (conn->out)
9074 flags |= MGMT_DEV_FOUND_INITIATED_CONN;
9075
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02009076 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02009077
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009078 /* We must ensure that the EIR Data fields are ordered and
9079 * unique. Keep it simple for now and avoid the problem by not
9080 * adding any BR/EDR data to the LE adv.
9081 */
9082 if (conn->le_adv_data_len > 0) {
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009083 skb_put_data(skb, conn->le_adv_data, conn->le_adv_data_len);
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009084 eir_len = conn->le_adv_data_len;
9085 } else {
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009086 if (name_len > 0) {
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009087 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
9088 name, name_len);
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009089 skb_put(skb, eir_len);
9090 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02009091
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009092 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) {
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009093 eir_len = eir_append_data(ev->eir, eir_len,
9094 EIR_CLASS_OF_DEV,
9095 conn->dev_class, 3);
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009096 skb_put(skb, 5);
9097 }
Alfonso Acostafd45ada2014-10-07 08:44:11 +00009098 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02009099
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009100 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009101
Luiz Augusto von Dentze9674142021-12-03 16:15:42 -08009102 mgmt_event_skb(skb, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02009103}
9104
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009105static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009106{
Johan Hedberg8962ee72011-01-20 12:40:27 +02009107 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009108
Johan Hedbergf5818c22014-12-05 13:36:02 +02009109 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009110
9111 *sk = cmd->sk;
9112 sock_hold(*sk);
9113
Johan Hedberga664b5b2011-02-19 12:06:02 -03009114 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009115}
9116
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009117static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02009118{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009119 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02009120 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02009121
Johan Hedbergb1078ad2012-02-09 17:21:16 +02009122 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
9123
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02009124 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02009125 mgmt_pending_remove(cmd);
9126}
9127
Johan Hedberg84c61d92014-08-01 11:13:30 +03009128bool mgmt_powering_down(struct hci_dev *hdev)
9129{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009130 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03009131 struct mgmt_mode *cp;
9132
Johan Hedberg333ae952015-03-17 13:48:47 +02009133 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03009134 if (!cmd)
9135 return false;
9136
9137 cp = cmd->param;
9138 if (!cp->val)
9139 return true;
9140
9141 return false;
9142}
9143
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009144void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009145 u8 link_type, u8 addr_type, u8 reason,
9146 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02009147{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009148 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009149 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009150
Johan Hedberg84c61d92014-08-01 11:13:30 +03009151 /* The connection is still in hci_conn_hash so test for 1
9152 * instead of 0 to know if this is the last one.
9153 */
9154 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9155 cancel_delayed_work(&hdev->power_off);
9156 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02009157 }
9158
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02009159 if (!mgmt_connected)
9160 return;
9161
Andre Guedes57eb7762013-10-30 19:01:41 -03009162 if (link_type != ACL_LINK && link_type != LE_LINK)
9163 return;
9164
Johan Hedberg744cf192011-11-08 20:40:14 +02009165 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02009166
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02009167 bacpy(&ev.addr.bdaddr, bdaddr);
9168 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9169 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02009170
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07009171 /* Report disconnects due to suspend */
9172 if (hdev->suspended)
9173 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
9174
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07009175 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009176
9177 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01009178 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009179
Johan Hedberg124f6e32012-02-09 13:50:12 +02009180 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009181 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009182}
9183
Marcel Holtmann78929242013-10-06 23:55:47 -07009184void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
9185 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02009186{
Andre Guedes3655bba2013-10-30 19:01:40 -03009187 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
9188 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009189 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009190
Jefferson Delfes36a75f12012-09-18 13:36:54 -04009191 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
9192 hdev);
9193
Johan Hedberg333ae952015-03-17 13:48:47 +02009194 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02009195 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07009196 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02009197
Andre Guedes3655bba2013-10-30 19:01:40 -03009198 cp = cmd->param;
9199
9200 if (bacmp(bdaddr, &cp->addr.bdaddr))
9201 return;
9202
9203 if (cp->addr.type != bdaddr_type)
9204 return;
9205
Johan Hedbergf5818c22014-12-05 13:36:02 +02009206 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009207 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02009208}
Johan Hedberg17d5c042011-01-22 06:09:08 +02009209
Marcel Holtmann445608d2013-10-06 23:55:48 -07009210void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9211 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02009212{
9213 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02009214
Johan Hedberg84c61d92014-08-01 11:13:30 +03009215 /* The connection is still in hci_conn_hash so test for 1
9216 * instead of 0 to know if this is the last one.
9217 */
9218 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
9219 cancel_delayed_work(&hdev->power_off);
9220 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02009221 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02009222
Johan Hedberg4c659c32011-11-07 23:13:39 +02009223 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009224 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02009225 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009226
Marcel Holtmann445608d2013-10-06 23:55:48 -07009227 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02009228}
Johan Hedberg980e1a52011-01-22 06:10:07 +02009229
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009230void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009231{
9232 struct mgmt_ev_pin_code_request ev;
9233
Johan Hedbergd8457692012-02-17 14:24:57 +02009234 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03009235 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02009236 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009237
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07009238 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009239}
9240
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009241void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9242 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009243{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009244 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009245
Johan Hedberg333ae952015-03-17 13:48:47 +02009246 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009247 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07009248 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009249
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009250 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009251 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009252}
9253
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009254void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
9255 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02009256{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009257 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009258
Johan Hedberg333ae952015-03-17 13:48:47 +02009259 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009260 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07009261 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02009262
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009263 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009264 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02009265}
Johan Hedberga5c29682011-02-19 12:05:57 -03009266
Johan Hedberg744cf192011-11-08 20:40:14 +02009267int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02009268 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009269 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03009270{
9271 struct mgmt_ev_user_confirm_request ev;
9272
Marcel Holtmann181d6952020-05-06 09:57:47 +02009273 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03009274
Johan Hedberg272d90d2012-02-09 15:26:12 +02009275 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009276 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07009277 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02009278 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03009279
Johan Hedberg744cf192011-11-08 20:40:14 +02009280 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009281 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03009282}
9283
Johan Hedberg272d90d2012-02-09 15:26:12 +02009284int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009285 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08009286{
9287 struct mgmt_ev_user_passkey_request ev;
9288
Marcel Holtmann181d6952020-05-06 09:57:47 +02009289 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08009290
Johan Hedberg272d90d2012-02-09 15:26:12 +02009291 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009292 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08009293
9294 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009295 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08009296}
9297
Brian Gix0df4c182011-11-16 13:53:13 -08009298static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009299 u8 link_type, u8 addr_type, u8 status,
9300 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03009301{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009302 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03009303
Johan Hedberg333ae952015-03-17 13:48:47 +02009304 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03009305 if (!cmd)
9306 return -ENOENT;
9307
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009308 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009309 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03009310
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009311 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03009312}
9313
Johan Hedberg744cf192011-11-08 20:40:14 +02009314int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009315 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009316{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009317 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009318 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009319}
9320
Johan Hedberg272d90d2012-02-09 15:26:12 +02009321int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009322 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009323{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009324 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009325 status,
9326 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009327}
Johan Hedberg2a611692011-02-19 12:06:00 -03009328
Brian Gix604086b2011-11-23 08:28:33 -08009329int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009330 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009331{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009332 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009333 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009334}
9335
Johan Hedberg272d90d2012-02-09 15:26:12 +02009336int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009337 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009338{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009339 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009340 status,
9341 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009342}
9343
Johan Hedberg92a25252012-09-06 18:39:26 +03009344int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
9345 u8 link_type, u8 addr_type, u32 passkey,
9346 u8 entered)
9347{
9348 struct mgmt_ev_passkey_notify ev;
9349
Marcel Holtmann181d6952020-05-06 09:57:47 +02009350 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03009351
9352 bacpy(&ev.addr.bdaddr, bdaddr);
9353 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9354 ev.passkey = __cpu_to_le32(passkey);
9355 ev.entered = entered;
9356
9357 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
9358}
9359
Johan Hedberge1e930f2014-09-08 17:09:49 -07009360void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03009361{
9362 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009363 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07009364 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03009365
Johan Hedberge1e930f2014-09-08 17:09:49 -07009366 bacpy(&ev.addr.bdaddr, &conn->dst);
9367 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
9368 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03009369
Johan Hedberge1e930f2014-09-08 17:09:49 -07009370 cmd = find_pairing(conn);
9371
9372 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
9373 cmd ? cmd->sk : NULL);
9374
Johan Hedberga511b352014-12-11 21:45:45 +02009375 if (cmd) {
9376 cmd->cmd_complete(cmd, status);
9377 mgmt_pending_remove(cmd);
9378 }
Johan Hedberg2a611692011-02-19 12:06:00 -03009379}
Johan Hedbergb312b1612011-03-16 14:29:37 +02009380
Marcel Holtmann464996a2013-10-15 14:26:24 -07009381void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009382{
9383 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07009384 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009385
9386 if (status) {
9387 u8 mgmt_err = mgmt_status(status);
9388 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009389 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009390 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009391 }
9392
Marcel Holtmann464996a2013-10-15 14:26:24 -07009393 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07009394 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009395 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009396 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02009397
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009398 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009399 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009400
Johan Hedberg47990ea2012-02-22 11:58:37 +02009401 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07009402 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009403
9404 if (match.sk)
9405 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009406}
9407
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009408static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02009409{
9410 struct cmd_lookup *match = data;
9411
Johan Hedberg90e70452012-02-23 23:09:40 +02009412 if (match->sk == NULL) {
9413 match->sk = cmd->sk;
9414 sock_hold(match->sk);
9415 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009416}
9417
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07009418void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
9419 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009420{
Johan Hedberg90e70452012-02-23 23:09:40 +02009421 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009422
Johan Hedberg92da6092013-03-15 17:06:55 -05009423 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
9424 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
9425 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02009426
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009427 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009428 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
9429 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009430 ext_info_changed(hdev, NULL);
9431 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009432
9433 if (match.sk)
9434 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009435}
9436
Marcel Holtmann7667da32013-10-15 14:26:27 -07009437void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02009438{
Johan Hedbergb312b1612011-03-16 14:29:37 +02009439 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009440 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009441
Johan Hedberg13928972013-03-15 17:07:00 -05009442 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07009443 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009444
9445 memset(&ev, 0, sizeof(ev));
9446 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009447 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009448
Johan Hedberg333ae952015-03-17 13:48:47 +02009449 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05009450 if (!cmd) {
9451 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02009452
Johan Hedberg13928972013-03-15 17:07:00 -05009453 /* If this is a HCI command related to powering on the
9454 * HCI dev don't send any mgmt signals.
9455 */
Johan Hedberg333ae952015-03-17 13:48:47 +02009456 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07009457 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009458 }
9459
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009460 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
9461 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009462 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009463}
Szymon Jancc35938b2011-03-22 13:12:21 +01009464
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009465static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
9466{
9467 int i;
9468
9469 for (i = 0; i < uuid_count; i++) {
9470 if (!memcmp(uuid, uuids[i], 16))
9471 return true;
9472 }
9473
9474 return false;
9475}
9476
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009477static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
9478{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009479 u16 parsed = 0;
9480
9481 while (parsed < eir_len) {
9482 u8 field_len = eir[0];
9483 u8 uuid[16];
9484 int i;
9485
9486 if (field_len == 0)
9487 break;
9488
9489 if (eir_len - parsed < field_len + 1)
9490 break;
9491
9492 switch (eir[1]) {
9493 case EIR_UUID16_ALL:
9494 case EIR_UUID16_SOME:
9495 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009496 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009497 uuid[13] = eir[i + 3];
9498 uuid[12] = eir[i + 2];
9499 if (has_uuid(uuid, uuid_count, uuids))
9500 return true;
9501 }
9502 break;
9503 case EIR_UUID32_ALL:
9504 case EIR_UUID32_SOME:
9505 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009506 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009507 uuid[15] = eir[i + 5];
9508 uuid[14] = eir[i + 4];
9509 uuid[13] = eir[i + 3];
9510 uuid[12] = eir[i + 2];
9511 if (has_uuid(uuid, uuid_count, uuids))
9512 return true;
9513 }
9514 break;
9515 case EIR_UUID128_ALL:
9516 case EIR_UUID128_SOME:
9517 for (i = 0; i + 17 <= field_len; i += 16) {
9518 memcpy(uuid, eir + i + 2, 16);
9519 if (has_uuid(uuid, uuid_count, uuids))
9520 return true;
9521 }
9522 break;
9523 }
9524
9525 parsed += field_len + 1;
9526 eir += field_len + 1;
9527 }
9528
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009529 return false;
9530}
9531
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009532static void restart_le_scan(struct hci_dev *hdev)
9533{
9534 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009535 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009536 return;
9537
9538 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
9539 hdev->discovery.scan_start +
9540 hdev->discovery.scan_duration))
9541 return;
9542
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02009543 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009544 DISCOV_LE_RESTART_DELAY);
9545}
9546
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009547static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
9548 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
9549{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009550 /* If a RSSI threshold has been specified, and
9551 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
9552 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
9553 * is set, let it through for further processing, as we might need to
9554 * restart the scan.
9555 *
9556 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
9557 * the results are also dropped.
9558 */
9559 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9560 (rssi == HCI_RSSI_INVALID ||
9561 (rssi < hdev->discovery.rssi &&
9562 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
9563 return false;
9564
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009565 if (hdev->discovery.uuid_count != 0) {
9566 /* If a list of UUIDs is provided in filter, results with no
9567 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009568 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009569 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
9570 hdev->discovery.uuids) &&
9571 !eir_has_uuids(scan_rsp, scan_rsp_len,
9572 hdev->discovery.uuid_count,
9573 hdev->discovery.uuids))
9574 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009575 }
9576
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009577 /* If duplicate filtering does not report RSSI changes, then restart
9578 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009579 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009580 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
9581 restart_le_scan(hdev);
9582
9583 /* Validate RSSI value against the RSSI threshold once more. */
9584 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9585 rssi < hdev->discovery.rssi)
9586 return false;
9587 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009588
9589 return true;
9590}
9591
Marcel Holtmann901801b2013-10-06 23:55:51 -07009592void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02009593 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
9594 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03009595{
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009596 struct sk_buff *skb;
9597 struct mgmt_ev_device_found *ev;
Johan Hedberge17acd42011-03-30 23:57:16 +03009598
Johan Hedberg75ce2082014-07-02 22:42:01 +03009599 /* Don't send events for a non-kernel initiated discovery. With
9600 * LE one exception is if we have pend_le_reports > 0 in which
9601 * case we're doing passive scanning and want these events.
9602 */
9603 if (!hci_discovery_active(hdev)) {
9604 if (link_type == ACL_LINK)
9605 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009606 if (link_type == LE_LINK &&
9607 list_empty(&hdev->pend_le_reports) &&
9608 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03009609 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009610 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03009611 }
Andre Guedes12602d02013-04-30 15:29:40 -03009612
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08009613 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009614 /* We are using service discovery */
9615 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
9616 scan_rsp_len))
9617 return;
9618 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01009619
Johan Hedberg78b781c2016-01-05 13:19:32 +02009620 if (hdev->discovery.limited) {
9621 /* Check for limited discoverable bit */
9622 if (dev_class) {
9623 if (!(dev_class[1] & 0x20))
9624 return;
9625 } else {
9626 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
9627 if (!flags || !(flags[0] & LE_AD_LIMITED))
9628 return;
9629 }
9630 }
9631
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009632 /* Allocate skb. The 5 extra bytes are for the potential CoD field */
9633 skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND,
9634 sizeof(*ev) + eir_len + scan_rsp_len + 5);
9635 if (!skb)
Marcel Holtmann901801b2013-10-06 23:55:51 -07009636 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03009637
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009638 ev = skb_put(skb, sizeof(*ev));
Johan Hedberg1dc06092012-01-15 21:01:23 +02009639
Marcel Holtmannda25cf62014-12-05 13:03:35 +01009640 /* In case of device discovery with BR/EDR devices (pre 1.2), the
9641 * RSSI value was reported as 0 when not available. This behavior
9642 * is kept when using device discovery. This is required for full
9643 * backwards compatibility with the API.
9644 *
9645 * However when using service discovery, the value 127 will be
9646 * returned when the RSSI is not available.
9647 */
Szymon Janc91200e92015-01-22 16:57:05 +01009648 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
9649 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01009650 rssi = 0;
9651
Johan Hedberg841c5642014-07-07 12:45:54 +03009652 bacpy(&ev->addr.bdaddr, bdaddr);
9653 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02009654 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02009655 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03009656
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009657 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009658 /* Copy EIR or advertising data into event */
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009659 skb_put_data(skb, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03009660
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009661 if (dev_class && !eir_get_data(eir, eir_len, EIR_CLASS_OF_DEV, NULL)) {
9662 u8 eir_cod[5];
9663
9664 eir_len += eir_append_data(eir_cod, 0, EIR_CLASS_OF_DEV,
9665 dev_class, 3);
9666 skb_put_data(skb, eir_cod, sizeof(eir_cod));
9667 }
Johan Hedberg1dc06092012-01-15 21:01:23 +02009668
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009669 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009670 /* Append scan response data to event */
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009671 skb_put_data(skb, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009672
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009673 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
Andre Guedesf8523592011-09-09 18:56:26 -03009674
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009675 mgmt_event_skb(skb, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03009676}
Johan Hedberga88a9652011-03-30 13:18:12 +03009677
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009678void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9679 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03009680{
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009681 struct sk_buff *skb;
Johan Hedbergb644ba32012-01-17 21:48:47 +02009682 struct mgmt_ev_device_found *ev;
Johan Hedbergb644ba32012-01-17 21:48:47 +02009683 u16 eir_len;
Archie Pusakaea13aed2021-11-25 15:04:36 +08009684 u32 flags;
Johan Hedberga88a9652011-03-30 13:18:12 +03009685
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009686 if (name_len)
9687 skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 2 + name_len);
9688 else
9689 skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 0);
Johan Hedberga88a9652011-03-30 13:18:12 +03009690
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009691 ev = skb_put(skb, sizeof(*ev));
Johan Hedbergb644ba32012-01-17 21:48:47 +02009692 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009693 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009694 ev->rssi = rssi;
9695
Archie Pusakaea13aed2021-11-25 15:04:36 +08009696 if (name) {
9697 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
9698 name_len);
9699 flags = 0;
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009700 skb_put(skb, eir_len);
Archie Pusakaea13aed2021-11-25 15:04:36 +08009701 } else {
9702 eir_len = 0;
9703 flags = MGMT_DEV_FOUND_NAME_REQUEST_FAILED;
9704 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02009705
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009706 ev->eir_len = cpu_to_le16(eir_len);
Archie Pusakaea13aed2021-11-25 15:04:36 +08009707 ev->flags = cpu_to_le32(flags);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009708
Luiz Augusto von Dentzcf1bce12021-12-03 16:15:41 -08009709 mgmt_event_skb(skb, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03009710}
Johan Hedberg314b2382011-04-27 10:29:57 -04009711
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009712void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04009713{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009714 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02009715
Marcel Holtmann181d6952020-05-06 09:57:47 +02009716 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03009717
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009718 memset(&ev, 0, sizeof(ev));
9719 ev.type = hdev->discovery.type;
9720 ev.discovering = discovering;
9721
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009722 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04009723}
Antti Julku5e762442011-08-25 16:48:02 +03009724
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07009725void mgmt_suspending(struct hci_dev *hdev, u8 state)
9726{
9727 struct mgmt_ev_controller_suspend ev;
9728
9729 ev.suspend_state = state;
9730 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
9731}
9732
9733void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
9734 u8 addr_type)
9735{
9736 struct mgmt_ev_controller_resume ev;
9737
9738 ev.wake_reason = reason;
9739 if (bdaddr) {
9740 bacpy(&ev.addr.bdaddr, bdaddr);
9741 ev.addr.type = addr_type;
9742 } else {
9743 memset(&ev.addr, 0, sizeof(ev.addr));
9744 }
9745
9746 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
9747}
9748
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009749static struct hci_mgmt_chan chan = {
9750 .channel = HCI_CHANNEL_CONTROL,
9751 .handler_count = ARRAY_SIZE(mgmt_handlers),
9752 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02009753 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009754};
9755
9756int mgmt_init(void)
9757{
9758 return hci_mgmt_chan_register(&chan);
9759}
9760
9761void mgmt_exit(void)
9762{
9763 hci_mgmt_chan_unregister(&chan);
9764}