blob: 08f67f91d427f2098fc1384a9cc201b49de6b653 [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"
Johan Hedberg03811012010-12-08 00:21:06 +020041
Johan Hedberg2da9c552012-02-17 14:39:28 +020042#define MGMT_VERSION 1
Marcel Holtmann79bf1182020-07-30 19:40:11 +020043#define MGMT_REVISION 18
Johan Hedberg02d98122010-12-13 21:07:04 +020044
Johan Hedberge70bb2e2012-02-13 16:59:33 +020045static const u16 mgmt_commands[] = {
46 MGMT_OP_READ_INDEX_LIST,
47 MGMT_OP_READ_INFO,
48 MGMT_OP_SET_POWERED,
49 MGMT_OP_SET_DISCOVERABLE,
50 MGMT_OP_SET_CONNECTABLE,
51 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030052 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020053 MGMT_OP_SET_LINK_SECURITY,
54 MGMT_OP_SET_SSP,
55 MGMT_OP_SET_HS,
56 MGMT_OP_SET_LE,
57 MGMT_OP_SET_DEV_CLASS,
58 MGMT_OP_SET_LOCAL_NAME,
59 MGMT_OP_ADD_UUID,
60 MGMT_OP_REMOVE_UUID,
61 MGMT_OP_LOAD_LINK_KEYS,
62 MGMT_OP_LOAD_LONG_TERM_KEYS,
63 MGMT_OP_DISCONNECT,
64 MGMT_OP_GET_CONNECTIONS,
65 MGMT_OP_PIN_CODE_REPLY,
66 MGMT_OP_PIN_CODE_NEG_REPLY,
67 MGMT_OP_SET_IO_CAPABILITY,
68 MGMT_OP_PAIR_DEVICE,
69 MGMT_OP_CANCEL_PAIR_DEVICE,
70 MGMT_OP_UNPAIR_DEVICE,
71 MGMT_OP_USER_CONFIRM_REPLY,
72 MGMT_OP_USER_CONFIRM_NEG_REPLY,
73 MGMT_OP_USER_PASSKEY_REPLY,
74 MGMT_OP_USER_PASSKEY_NEG_REPLY,
75 MGMT_OP_READ_LOCAL_OOB_DATA,
76 MGMT_OP_ADD_REMOTE_OOB_DATA,
77 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
78 MGMT_OP_START_DISCOVERY,
79 MGMT_OP_STOP_DISCOVERY,
80 MGMT_OP_CONFIRM_NAME,
81 MGMT_OP_BLOCK_DEVICE,
82 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070083 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030084 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030085 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070086 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070087 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080088 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080089 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020090 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020091 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020092 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030093 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020094 MGMT_OP_ADD_DEVICE,
95 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030096 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020097 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020098 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020099 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200100 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100101 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700102 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700103 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700104 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700105 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700106 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100107 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200108 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200109 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200110 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000111 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000112 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200113 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200114 MGMT_OP_READ_EXP_FEATURES_INFO,
115 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000116 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
117 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200118 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
119 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200120 MGMT_OP_GET_DEVICE_FLAGS,
121 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200122 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200123 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200124 MGMT_OP_REMOVE_ADV_MONITOR,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200125};
126
127static const u16 mgmt_events[] = {
128 MGMT_EV_CONTROLLER_ERROR,
129 MGMT_EV_INDEX_ADDED,
130 MGMT_EV_INDEX_REMOVED,
131 MGMT_EV_NEW_SETTINGS,
132 MGMT_EV_CLASS_OF_DEV_CHANGED,
133 MGMT_EV_LOCAL_NAME_CHANGED,
134 MGMT_EV_NEW_LINK_KEY,
135 MGMT_EV_NEW_LONG_TERM_KEY,
136 MGMT_EV_DEVICE_CONNECTED,
137 MGMT_EV_DEVICE_DISCONNECTED,
138 MGMT_EV_CONNECT_FAILED,
139 MGMT_EV_PIN_CODE_REQUEST,
140 MGMT_EV_USER_CONFIRM_REQUEST,
141 MGMT_EV_USER_PASSKEY_REQUEST,
142 MGMT_EV_AUTH_FAILED,
143 MGMT_EV_DEVICE_FOUND,
144 MGMT_EV_DISCOVERING,
145 MGMT_EV_DEVICE_BLOCKED,
146 MGMT_EV_DEVICE_UNBLOCKED,
147 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300148 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800149 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700150 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200151 MGMT_EV_DEVICE_ADDED,
152 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300153 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200154 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200155 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200156 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700157 MGMT_EV_EXT_INDEX_ADDED,
158 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700159 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700160 MGMT_EV_ADVERTISING_ADDED,
161 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200162 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200163 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200164 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200165 MGMT_EV_DEVICE_FLAGS_CHANGED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700166 MGMT_EV_CONTROLLER_SUSPEND,
167 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200168};
169
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700170static const u16 mgmt_untrusted_commands[] = {
171 MGMT_OP_READ_INDEX_LIST,
172 MGMT_OP_READ_INFO,
173 MGMT_OP_READ_UNCONF_INDEX_LIST,
174 MGMT_OP_READ_CONFIG_INFO,
175 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200176 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200177 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200178 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000179 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200180 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700181};
182
183static const u16 mgmt_untrusted_events[] = {
184 MGMT_EV_INDEX_ADDED,
185 MGMT_EV_INDEX_REMOVED,
186 MGMT_EV_NEW_SETTINGS,
187 MGMT_EV_CLASS_OF_DEV_CHANGED,
188 MGMT_EV_LOCAL_NAME_CHANGED,
189 MGMT_EV_UNCONF_INDEX_ADDED,
190 MGMT_EV_UNCONF_INDEX_REMOVED,
191 MGMT_EV_NEW_CONFIG_OPTIONS,
192 MGMT_EV_EXT_INDEX_ADDED,
193 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200194 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200195 MGMT_EV_EXP_FEATURE_CHANGED,
Miao-chen Choub52729f2020-06-17 16:39:16 +0200196 MGMT_EV_ADV_MONITOR_ADDED,
Miao-chen Choucdde92e2020-06-17 16:39:17 +0200197 MGMT_EV_ADV_MONITOR_REMOVED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700198};
199
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800200#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200201
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200202#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
203 "\x00\x00\x00\x00\x00\x00\x00\x00"
204
Johan Hedbergca69b792011-11-11 18:10:00 +0200205/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000206static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200207 MGMT_STATUS_SUCCESS,
208 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
209 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
210 MGMT_STATUS_FAILED, /* Hardware Failure */
211 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
212 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200213 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200214 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
215 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
216 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
217 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
218 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
219 MGMT_STATUS_BUSY, /* Command Disallowed */
220 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
221 MGMT_STATUS_REJECTED, /* Rejected Security */
222 MGMT_STATUS_REJECTED, /* Rejected Personal */
223 MGMT_STATUS_TIMEOUT, /* Host Timeout */
224 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
225 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
226 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
227 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
228 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
229 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
230 MGMT_STATUS_BUSY, /* Repeated Attempts */
231 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
232 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
233 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
234 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
235 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
236 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
237 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
238 MGMT_STATUS_FAILED, /* Unspecified Error */
239 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
240 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
241 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
242 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
243 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
244 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
245 MGMT_STATUS_FAILED, /* Unit Link Key Used */
246 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
247 MGMT_STATUS_TIMEOUT, /* Instant Passed */
248 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
249 MGMT_STATUS_FAILED, /* Transaction Collision */
Yu Liu8f939b42021-04-19 16:53:30 -0700250 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200251 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
252 MGMT_STATUS_REJECTED, /* QoS Rejected */
253 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
254 MGMT_STATUS_REJECTED, /* Insufficient Security */
255 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
Yu Liu8f939b42021-04-19 16:53:30 -0700256 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200257 MGMT_STATUS_BUSY, /* Role Switch Pending */
Yu Liu8f939b42021-04-19 16:53:30 -0700258 MGMT_STATUS_FAILED, /* Reserved for future use */
Johan Hedbergca69b792011-11-11 18:10:00 +0200259 MGMT_STATUS_FAILED, /* Slot Violation */
260 MGMT_STATUS_FAILED, /* Role Switch Failed */
261 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
262 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
263 MGMT_STATUS_BUSY, /* Host Busy Pairing */
264 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
265 MGMT_STATUS_BUSY, /* Controller Busy */
266 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
267 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
268 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
269 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
270 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
271};
272
273static u8 mgmt_status(u8 hci_status)
274{
275 if (hci_status < ARRAY_SIZE(mgmt_status_table))
276 return mgmt_status_table[hci_status];
277
278 return MGMT_STATUS_FAILED;
279}
280
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700281static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
282 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700283{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700284 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
285 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700286}
287
Marcel Holtmann72000df2015-03-16 16:11:21 -0700288static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
289 u16 len, int flag, struct sock *skip_sk)
290{
291 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
292 flag, skip_sk);
293}
294
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200295static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
296 struct sock *skip_sk)
297{
298 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700299 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200300}
301
Johan Hedberg85813a72015-10-21 18:02:59 +0300302static u8 le_addr_type(u8 mgmt_addr_type)
303{
304 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
305 return ADDR_LE_DEV_PUBLIC;
306 else
307 return ADDR_LE_DEV_RANDOM;
308}
309
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200310void mgmt_fill_version_info(void *ver)
311{
312 struct mgmt_rp_read_version *rp = ver;
313
314 rp->version = MGMT_VERSION;
315 rp->revision = cpu_to_le16(MGMT_REVISION);
316}
317
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300318static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
319 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200320{
321 struct mgmt_rp_read_version rp;
322
Marcel Holtmann181d6952020-05-06 09:57:47 +0200323 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200324
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200325 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200326
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200327 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
328 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200329}
330
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300331static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
332 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200333{
334 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700335 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200336 size_t rp_size;
337 int i, err;
338
Marcel Holtmann181d6952020-05-06 09:57:47 +0200339 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200340
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700341 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
342 num_commands = ARRAY_SIZE(mgmt_commands);
343 num_events = ARRAY_SIZE(mgmt_events);
344 } else {
345 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
346 num_events = ARRAY_SIZE(mgmt_untrusted_events);
347 }
348
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200349 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
350
351 rp = kmalloc(rp_size, GFP_KERNEL);
352 if (!rp)
353 return -ENOMEM;
354
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700355 rp->num_commands = cpu_to_le16(num_commands);
356 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200357
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700358 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
359 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200360
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700361 for (i = 0; i < num_commands; i++, opcode++)
362 put_unaligned_le16(mgmt_commands[i], opcode);
363
364 for (i = 0; i < num_events; i++, opcode++)
365 put_unaligned_le16(mgmt_events[i], opcode);
366 } else {
367 __le16 *opcode = rp->opcodes;
368
369 for (i = 0; i < num_commands; i++, opcode++)
370 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
371
372 for (i = 0; i < num_events; i++, opcode++)
373 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
374 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200375
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200376 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
377 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200378 kfree(rp);
379
380 return err;
381}
382
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300383static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
384 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200385{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200386 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200387 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200388 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200389 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300390 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391
Marcel Holtmann181d6952020-05-06 09:57:47 +0200392 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200393
394 read_lock(&hci_dev_list_lock);
395
396 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300397 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200398 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700399 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700400 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401 }
402
Johan Hedberga38528f2011-01-22 06:46:43 +0200403 rp_len = sizeof(*rp) + (2 * count);
404 rp = kmalloc(rp_len, GFP_ATOMIC);
405 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100406 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200407 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100408 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200409
Johan Hedberg476e44c2012-10-19 20:10:46 +0300410 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200411 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700412 if (hci_dev_test_flag(d, HCI_SETUP) ||
413 hci_dev_test_flag(d, HCI_CONFIG) ||
414 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200415 continue;
416
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200417 /* Devices marked as raw-only are neither configured
418 * nor unconfigured controllers.
419 */
420 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700421 continue;
422
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200423 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700424 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700425 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200426 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700427 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428 }
429
Johan Hedberg476e44c2012-10-19 20:10:46 +0300430 rp->num_controllers = cpu_to_le16(count);
431 rp_len = sizeof(*rp) + (2 * count);
432
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200433 read_unlock(&hci_dev_list_lock);
434
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200435 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
436 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200437
Johan Hedberga38528f2011-01-22 06:46:43 +0200438 kfree(rp);
439
440 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200441}
442
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200443static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
444 void *data, u16 data_len)
445{
446 struct mgmt_rp_read_unconf_index_list *rp;
447 struct hci_dev *d;
448 size_t rp_len;
449 u16 count;
450 int err;
451
Marcel Holtmann181d6952020-05-06 09:57:47 +0200452 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200453
454 read_lock(&hci_dev_list_lock);
455
456 count = 0;
457 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200458 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700459 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460 count++;
461 }
462
463 rp_len = sizeof(*rp) + (2 * count);
464 rp = kmalloc(rp_len, GFP_ATOMIC);
465 if (!rp) {
466 read_unlock(&hci_dev_list_lock);
467 return -ENOMEM;
468 }
469
470 count = 0;
471 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700472 if (hci_dev_test_flag(d, HCI_SETUP) ||
473 hci_dev_test_flag(d, HCI_CONFIG) ||
474 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200475 continue;
476
477 /* Devices marked as raw-only are neither configured
478 * nor unconfigured controllers.
479 */
480 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
481 continue;
482
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200483 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700484 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200485 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200486 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200487 }
488 }
489
490 rp->num_controllers = cpu_to_le16(count);
491 rp_len = sizeof(*rp) + (2 * count);
492
493 read_unlock(&hci_dev_list_lock);
494
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200495 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
496 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200497
498 kfree(rp);
499
500 return err;
501}
502
Marcel Holtmann96f14742015-03-14 19:27:57 -0700503static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
504 void *data, u16 data_len)
505{
506 struct mgmt_rp_read_ext_index_list *rp;
507 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700508 u16 count;
509 int err;
510
Marcel Holtmann181d6952020-05-06 09:57:47 +0200511 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700512
513 read_lock(&hci_dev_list_lock);
514
515 count = 0;
516 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200517 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700518 count++;
519 }
520
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600521 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700522 if (!rp) {
523 read_unlock(&hci_dev_list_lock);
524 return -ENOMEM;
525 }
526
527 count = 0;
528 list_for_each_entry(d, &hci_dev_list, list) {
529 if (hci_dev_test_flag(d, HCI_SETUP) ||
530 hci_dev_test_flag(d, HCI_CONFIG) ||
531 hci_dev_test_flag(d, HCI_USER_CHANNEL))
532 continue;
533
534 /* Devices marked as raw-only are neither configured
535 * nor unconfigured controllers.
536 */
537 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
538 continue;
539
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200540 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700541 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
542 rp->entry[count].type = 0x01;
543 else
544 rp->entry[count].type = 0x00;
545 } else if (d->dev_type == HCI_AMP) {
546 rp->entry[count].type = 0x02;
547 } else {
548 continue;
549 }
550
551 rp->entry[count].bus = d->bus;
552 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200553 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700554 }
555
556 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700557
558 read_unlock(&hci_dev_list_lock);
559
560 /* If this command is called at least once, then all the
561 * default index and unconfigured index events are disabled
562 * and from now on only extended index events are used.
563 */
564 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
565 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
566 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
567
568 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600569 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
570 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700571
572 kfree(rp);
573
574 return err;
575}
576
Marcel Holtmanndbece372014-07-04 18:11:55 +0200577static bool is_configured(struct hci_dev *hdev)
578{
579 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700580 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200581 return false;
582
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800583 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
584 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200585 !bacmp(&hdev->public_addr, BDADDR_ANY))
586 return false;
587
588 return true;
589}
590
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200591static __le32 get_missing_options(struct hci_dev *hdev)
592{
593 u32 options = 0;
594
Marcel Holtmanndbece372014-07-04 18:11:55 +0200595 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700596 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200597 options |= MGMT_OPTION_EXTERNAL_CONFIG;
598
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800599 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
600 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200601 !bacmp(&hdev->public_addr, BDADDR_ANY))
602 options |= MGMT_OPTION_PUBLIC_ADDRESS;
603
604 return cpu_to_le32(options);
605}
606
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200607static int new_options(struct hci_dev *hdev, struct sock *skip)
608{
609 __le32 options = get_missing_options(hdev);
610
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200611 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
612 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200613}
614
Marcel Holtmanndbece372014-07-04 18:11:55 +0200615static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
616{
617 __le32 options = get_missing_options(hdev);
618
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200619 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
620 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200621}
622
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200623static int read_config_info(struct sock *sk, struct hci_dev *hdev,
624 void *data, u16 data_len)
625{
626 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200627 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200628
Marcel Holtmann181d6952020-05-06 09:57:47 +0200629 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200630
631 hci_dev_lock(hdev);
632
633 memset(&rp, 0, sizeof(rp));
634 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200635
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200636 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
637 options |= MGMT_OPTION_EXTERNAL_CONFIG;
638
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200639 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200640 options |= MGMT_OPTION_PUBLIC_ADDRESS;
641
642 rp.supported_options = cpu_to_le32(options);
643 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200644
645 hci_dev_unlock(hdev);
646
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200647 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
648 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649}
650
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530651static u32 get_supported_phys(struct hci_dev *hdev)
652{
653 u32 supported_phys = 0;
654
655 if (lmp_bredr_capable(hdev)) {
656 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
657
658 if (hdev->features[0][0] & LMP_3SLOT)
659 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
660
661 if (hdev->features[0][0] & LMP_5SLOT)
662 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
663
664 if (lmp_edr_2m_capable(hdev)) {
665 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
666
667 if (lmp_edr_3slot_capable(hdev))
668 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
669
670 if (lmp_edr_5slot_capable(hdev))
671 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
672
673 if (lmp_edr_3m_capable(hdev)) {
674 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
675
676 if (lmp_edr_3slot_capable(hdev))
677 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
678
679 if (lmp_edr_5slot_capable(hdev))
680 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
681 }
682 }
683 }
684
685 if (lmp_le_capable(hdev)) {
686 supported_phys |= MGMT_PHY_LE_1M_TX;
687 supported_phys |= MGMT_PHY_LE_1M_RX;
688
689 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
690 supported_phys |= MGMT_PHY_LE_2M_TX;
691 supported_phys |= MGMT_PHY_LE_2M_RX;
692 }
693
694 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
695 supported_phys |= MGMT_PHY_LE_CODED_TX;
696 supported_phys |= MGMT_PHY_LE_CODED_RX;
697 }
698 }
699
700 return supported_phys;
701}
702
703static u32 get_selected_phys(struct hci_dev *hdev)
704{
705 u32 selected_phys = 0;
706
707 if (lmp_bredr_capable(hdev)) {
708 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
709
710 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
711 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
712
713 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
714 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
715
716 if (lmp_edr_2m_capable(hdev)) {
717 if (!(hdev->pkt_type & HCI_2DH1))
718 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
719
720 if (lmp_edr_3slot_capable(hdev) &&
721 !(hdev->pkt_type & HCI_2DH3))
722 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
723
724 if (lmp_edr_5slot_capable(hdev) &&
725 !(hdev->pkt_type & HCI_2DH5))
726 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
727
728 if (lmp_edr_3m_capable(hdev)) {
729 if (!(hdev->pkt_type & HCI_3DH1))
730 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
731
732 if (lmp_edr_3slot_capable(hdev) &&
733 !(hdev->pkt_type & HCI_3DH3))
734 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
735
736 if (lmp_edr_5slot_capable(hdev) &&
737 !(hdev->pkt_type & HCI_3DH5))
738 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
739 }
740 }
741 }
742
743 if (lmp_le_capable(hdev)) {
744 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
745 selected_phys |= MGMT_PHY_LE_1M_TX;
746
747 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
748 selected_phys |= MGMT_PHY_LE_1M_RX;
749
750 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
751 selected_phys |= MGMT_PHY_LE_2M_TX;
752
753 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
754 selected_phys |= MGMT_PHY_LE_2M_RX;
755
756 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
757 selected_phys |= MGMT_PHY_LE_CODED_TX;
758
759 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
760 selected_phys |= MGMT_PHY_LE_CODED_RX;
761 }
762
763 return selected_phys;
764}
765
766static u32 get_configurable_phys(struct hci_dev *hdev)
767{
768 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
769 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
770}
771
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200772static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200773{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200774 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200776 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300777 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800778 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300779 settings |= MGMT_SETTING_CONNECTABLE;
780 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200781
Andre Guedesed3fa312012-07-24 15:03:46 -0300782 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500783 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
784 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 settings |= MGMT_SETTING_BREDR;
786 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700787
788 if (lmp_ssp_capable(hdev)) {
789 settings |= MGMT_SETTING_SSP;
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -0700790 if (IS_ENABLED(CONFIG_BT_HS))
791 settings |= MGMT_SETTING_HS;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700792 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800793
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800794 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800795 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000796
Alain Michaud00bce3f2020-03-05 16:14:59 +0000797 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000798 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000799 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700800 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100801
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300802 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200803 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300804 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200805 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800806 settings |= MGMT_SETTING_STATIC_ADDRESS;
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +0530807
808 /* When the experimental feature for LL Privacy support is
809 * enabled, then advertising is no longer supported.
810 */
811 if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
812 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300813 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200814
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200815 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
816 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200817 settings |= MGMT_SETTING_CONFIGURATION;
818
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530819 settings |= MGMT_SETTING_PHY_CONFIGURATION;
820
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200821 return settings;
822}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200823
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200824static u32 get_current_settings(struct hci_dev *hdev)
825{
826 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200827
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200828 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100829 settings |= MGMT_SETTING_POWERED;
830
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700831 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 settings |= MGMT_SETTING_CONNECTABLE;
833
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700834 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500835 settings |= MGMT_SETTING_FAST_CONNECTABLE;
836
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700837 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200838 settings |= MGMT_SETTING_DISCOVERABLE;
839
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700840 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300841 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200842
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700843 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200844 settings |= MGMT_SETTING_BREDR;
845
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700846 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200847 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200848
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700849 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200850 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200851
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700852 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200853 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200854
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700855 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200856 settings |= MGMT_SETTING_HS;
857
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700858 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300859 settings |= MGMT_SETTING_ADVERTISING;
860
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800862 settings |= MGMT_SETTING_SECURE_CONN;
863
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700864 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800865 settings |= MGMT_SETTING_DEBUG_KEYS;
866
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700867 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200868 settings |= MGMT_SETTING_PRIVACY;
869
Marcel Holtmann93690c22015-03-06 10:11:21 -0800870 /* The current setting for static address has two purposes. The
871 * first is to indicate if the static address will be used and
872 * the second is to indicate if it is actually set.
873 *
874 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700875 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800876 * address is actually used decides if the flag is set or not.
877 *
878 * For single mode LE only controllers and dual-mode controllers
879 * with BR/EDR disabled, the existence of the static address will
880 * be evaluated.
881 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700882 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700883 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800884 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
885 if (bacmp(&hdev->static_addr, BDADDR_ANY))
886 settings |= MGMT_SETTING_STATIC_ADDRESS;
887 }
888
Alain Michaud00bce3f2020-03-05 16:14:59 +0000889 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
890 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
891
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200892 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200893}
894
Johan Hedberg333ae952015-03-17 13:48:47 +0200895static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
896{
897 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
898}
899
Johan Hedberg333ae952015-03-17 13:48:47 +0200900static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
901 struct hci_dev *hdev,
902 const void *data)
903{
904 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
905}
906
Johan Hedbergf2252572015-11-18 12:49:20 +0200907u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300908{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200909 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300910
911 /* If there's a pending mgmt command the flags will not yet have
912 * their final values, so check for this first.
913 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200914 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300915 if (cmd) {
916 struct mgmt_mode *cp = cmd->param;
917 if (cp->val == 0x01)
918 return LE_AD_GENERAL;
919 else if (cp->val == 0x02)
920 return LE_AD_LIMITED;
921 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700922 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300923 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700924 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300925 return LE_AD_GENERAL;
926 }
927
928 return 0;
929}
930
Johan Hedbergf2252572015-11-18 12:49:20 +0200931bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700932{
933 struct mgmt_pending_cmd *cmd;
934
935 /* If there's a pending mgmt command the flag will not yet have
936 * it's final value, so check for this first.
937 */
938 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
939 if (cmd) {
940 struct mgmt_mode *cp = cmd->param;
941
942 return cp->val;
943 }
944
945 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
946}
947
Johan Hedberg7d785252011-12-15 00:47:39 +0200948static void service_cache_off(struct work_struct *work)
949{
950 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300951 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500952 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200953
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700954 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200955 return;
956
Johan Hedberg890ea892013-03-15 17:06:52 -0500957 hci_req_init(&req, hdev);
958
Johan Hedberg7d785252011-12-15 00:47:39 +0200959 hci_dev_lock(hdev);
960
Johan Hedbergb1a89172015-11-25 16:15:42 +0200961 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200962 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200963
964 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500965
966 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200967}
968
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200969static void rpa_expired(struct work_struct *work)
970{
971 struct hci_dev *hdev = container_of(work, struct hci_dev,
972 rpa_expired.work);
973 struct hci_request req;
974
Marcel Holtmann181d6952020-05-06 09:57:47 +0200975 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200976
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700977 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200978
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700979 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200980 return;
981
982 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200983 * controller happens in the hci_req_enable_advertising()
984 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200985 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200986 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530987 if (ext_adv_capable(hdev))
988 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
989 else
990 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200991 hci_req_run(&req, NULL);
992}
993
Johan Hedberg6a919082012-02-28 06:17:26 +0200994static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200995{
Marcel Holtmann238be782015-03-13 02:11:06 -0700996 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200997 return;
998
Johan Hedberg4f87da82012-03-02 19:55:56 +0200999 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001000 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001001
Johan Hedberg4f87da82012-03-02 19:55:56 +02001002 /* Non-mgmt controlled devices get this bit set
1003 * implicitly so that pairing works for them, however
1004 * for mgmt we require user-space to explicitly enable
1005 * it
1006 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001007 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001008}
1009
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001010static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001011 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001012{
1013 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001014
Marcel Holtmann181d6952020-05-06 09:57:47 +02001015 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001017 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001018
Johan Hedberg03811012010-12-08 00:21:06 +02001019 memset(&rp, 0, sizeof(rp));
1020
Johan Hedberg03811012010-12-08 00:21:06 +02001021 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001022
1023 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001024 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001025
1026 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1027 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1028
1029 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001030
1031 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001032 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001035
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001036 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1037 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001038}
1039
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001040static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1041{
1042 u16 eir_len = 0;
1043 size_t name_len;
1044
1045 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1046 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1047 hdev->dev_class, 3);
1048
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001049 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1050 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1051 hdev->appearance);
1052
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001053 name_len = strlen(hdev->dev_name);
1054 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1055 hdev->dev_name, name_len);
1056
1057 name_len = strlen(hdev->short_name);
1058 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1059 hdev->short_name, name_len);
1060
1061 return eir_len;
1062}
1063
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001064static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1065 void *data, u16 data_len)
1066{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001067 char buf[512];
1068 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001069 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001070
Marcel Holtmann181d6952020-05-06 09:57:47 +02001071 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001072
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001073 memset(&buf, 0, sizeof(buf));
1074
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001075 hci_dev_lock(hdev);
1076
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001077 bacpy(&rp->bdaddr, &hdev->bdaddr);
1078
1079 rp->version = hdev->hci_ver;
1080 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1081
1082 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1083 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001084
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001085
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001086 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001087 rp->eir_len = cpu_to_le16(eir_len);
1088
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001089 hci_dev_unlock(hdev);
1090
1091 /* If this command is called at least once, then the events
1092 * for class of device and local name changes are disabled
1093 * and only the new extended controller information event
1094 * is used.
1095 */
1096 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1097 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1098 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1099
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001100 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1101 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001102}
1103
1104static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1105{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001106 char buf[512];
1107 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1108 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001109
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001110 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001111
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001112 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1113 ev->eir_len = cpu_to_le16(eir_len);
1114
1115 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1116 sizeof(*ev) + eir_len,
1117 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001118}
1119
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001120static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001121{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001122 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001123
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001124 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1125 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001126}
1127
Marcel Holtmann1904a852015-01-11 13:50:44 -08001128static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001129{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001130 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001131
Johan Hedberga3172b72014-02-28 09:33:44 +02001132 if (hci_conn_count(hdev) == 0) {
1133 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001134 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001135 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001136}
1137
Johan Hedbergf2252572015-11-18 12:49:20 +02001138void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001139{
1140 struct mgmt_ev_advertising_added ev;
1141
1142 ev.instance = instance;
1143
1144 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1145}
1146
Johan Hedbergf2252572015-11-18 12:49:20 +02001147void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1148 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001149{
1150 struct mgmt_ev_advertising_removed ev;
1151
1152 ev.instance = instance;
1153
1154 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1155}
1156
Florian Grandel7816b822015-06-18 03:16:45 +02001157static void cancel_adv_timeout(struct hci_dev *hdev)
1158{
1159 if (hdev->adv_instance_timeout) {
1160 hdev->adv_instance_timeout = 0;
1161 cancel_delayed_work(&hdev->adv_instance_expire);
1162 }
1163}
1164
Johan Hedberg8b064a32014-02-24 14:52:22 +02001165static int clean_up_hci_state(struct hci_dev *hdev)
1166{
1167 struct hci_request req;
1168 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001169 bool discov_stopped;
1170 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001171
1172 hci_req_init(&req, hdev);
1173
1174 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1175 test_bit(HCI_PSCAN, &hdev->flags)) {
1176 u8 scan = 0x00;
1177 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1178 }
1179
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001180 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001181
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001182 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001183 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001184
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001185 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186
1187 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001188 /* 0x15 == Terminated due to Power Off */
1189 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001190 }
1191
Johan Hedberg23a48092014-07-08 16:05:06 +03001192 err = hci_req_run(&req, clean_up_hci_complete);
1193 if (!err && discov_stopped)
1194 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1195
1196 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001197}
1198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001199static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001200 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001202 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001203 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001204 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205
Marcel Holtmann181d6952020-05-06 09:57:47 +02001206 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberga7e80f22013-01-09 16:05:19 +02001208 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001212 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberg333ae952015-03-17 13:48:47 +02001214 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001215 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1216 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001217 goto failed;
1218 }
1219
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001220 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001221 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 goto failed;
1223 }
1224
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001225 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1226 if (!cmd) {
1227 err = -ENOMEM;
1228 goto failed;
1229 }
1230
Johan Hedberg8b064a32014-02-24 14:52:22 +02001231 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001232 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001233 err = 0;
1234 } else {
1235 /* Disconnect connections, stop scans, etc */
1236 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001237 if (!err)
1238 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1239 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001240
Johan Hedberg8b064a32014-02-24 14:52:22 +02001241 /* ENODATA means there were no HCI commands queued */
1242 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001243 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001244 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1245 err = 0;
1246 }
1247 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001248
1249failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001250 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001251 return err;
1252}
1253
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001254static int new_settings(struct hci_dev *hdev, struct sock *skip)
1255{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001256 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001257
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001258 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1259 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001260}
1261
Johan Hedberg91a668b2014-07-09 13:28:26 +03001262int mgmt_new_settings(struct hci_dev *hdev)
1263{
1264 return new_settings(hdev, NULL);
1265}
1266
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001267struct cmd_lookup {
1268 struct sock *sk;
1269 struct hci_dev *hdev;
1270 u8 mgmt_status;
1271};
1272
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001273static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001274{
1275 struct cmd_lookup *match = data;
1276
1277 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1278
1279 list_del(&cmd->list);
1280
1281 if (match->sk == NULL) {
1282 match->sk = cmd->sk;
1283 sock_hold(match->sk);
1284 }
1285
1286 mgmt_pending_free(cmd);
1287}
1288
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001289static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001290{
1291 u8 *status = data;
1292
Johan Hedberga69e8372015-03-06 21:08:53 +02001293 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001294 mgmt_pending_remove(cmd);
1295}
1296
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001297static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001298{
1299 if (cmd->cmd_complete) {
1300 u8 *status = data;
1301
1302 cmd->cmd_complete(cmd, *status);
1303 mgmt_pending_remove(cmd);
1304
1305 return;
1306 }
1307
1308 cmd_status_rsp(cmd, data);
1309}
1310
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001311static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001312{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001313 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1314 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001315}
1316
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001317static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001318{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001319 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1320 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001321}
1322
Johan Hedberge6fe7982013-10-02 15:45:22 +03001323static u8 mgmt_bredr_support(struct hci_dev *hdev)
1324{
1325 if (!lmp_bredr_capable(hdev))
1326 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001327 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001328 return MGMT_STATUS_REJECTED;
1329 else
1330 return MGMT_STATUS_SUCCESS;
1331}
1332
1333static u8 mgmt_le_support(struct hci_dev *hdev)
1334{
1335 if (!lmp_le_capable(hdev))
1336 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001337 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001338 return MGMT_STATUS_REJECTED;
1339 else
1340 return MGMT_STATUS_SUCCESS;
1341}
1342
Johan Hedbergaed1a882015-11-22 17:24:44 +03001343void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001344{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001345 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001346
Marcel Holtmann181d6952020-05-06 09:57:47 +02001347 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348
1349 hci_dev_lock(hdev);
1350
Johan Hedberg333ae952015-03-17 13:48:47 +02001351 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001352 if (!cmd)
1353 goto unlock;
1354
1355 if (status) {
1356 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001357 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001358 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001359 goto remove_cmd;
1360 }
1361
Johan Hedbergaed1a882015-11-22 17:24:44 +03001362 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1363 hdev->discov_timeout > 0) {
1364 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1365 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001366 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001367
1368 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001369 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001370
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001371remove_cmd:
1372 mgmt_pending_remove(cmd);
1373
1374unlock:
1375 hci_dev_unlock(hdev);
1376}
1377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001379 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001380{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001381 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001382 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001383 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001384 int err;
1385
Marcel Holtmann181d6952020-05-06 09:57:47 +02001386 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001387
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001388 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1389 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001390 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1391 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001392
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001393 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001394 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1395 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001396
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001397 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001398
1399 /* Disabling discoverable requires that no timeout is set,
1400 * and enabling limited discoverable requires a timeout.
1401 */
1402 if ((cp->val == 0x00 && timeout > 0) ||
1403 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001404 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1405 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001406
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001407 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001409 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001410 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1411 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001412 goto failed;
1413 }
1414
Johan Hedberg333ae952015-03-17 13:48:47 +02001415 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1416 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1418 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001419 goto failed;
1420 }
1421
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001422 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001423 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1424 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001425 goto failed;
1426 }
1427
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001428 if (hdev->advertising_paused) {
1429 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1430 MGMT_STATUS_BUSY);
1431 goto failed;
1432 }
1433
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001434 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001435 bool changed = false;
1436
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001437 /* Setting limited discoverable when powered off is
1438 * not a valid operation since it requires a timeout
1439 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1440 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001441 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001442 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001443 changed = true;
1444 }
1445
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001446 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001447 if (err < 0)
1448 goto failed;
1449
1450 if (changed)
1451 err = new_settings(hdev, sk);
1452
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001453 goto failed;
1454 }
1455
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001456 /* If the current mode is the same, then just update the timeout
1457 * value with the new value. And if only the timeout gets updated,
1458 * then no need for any HCI transactions.
1459 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001460 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1461 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1462 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001463 cancel_delayed_work(&hdev->discov_off);
1464 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001465
Marcel Holtmann36261542013-10-15 08:28:51 -07001466 if (cp->val && hdev->discov_timeout > 0) {
1467 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001468 queue_delayed_work(hdev->req_workqueue,
1469 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001470 }
1471
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001472 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001473 goto failed;
1474 }
1475
1476 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1477 if (!cmd) {
1478 err = -ENOMEM;
1479 goto failed;
1480 }
1481
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001482 /* Cancel any potential discoverable timeout that might be
1483 * still active and store new timeout value. The arming of
1484 * the timeout happens in the complete handler.
1485 */
1486 cancel_delayed_work(&hdev->discov_off);
1487 hdev->discov_timeout = timeout;
1488
Johan Hedbergaed1a882015-11-22 17:24:44 +03001489 if (cp->val)
1490 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1491 else
1492 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1493
Johan Hedbergb456f872013-10-19 23:38:22 +03001494 /* Limited discoverable mode */
1495 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001496 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001497 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001498 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001499
Johan Hedbergaed1a882015-11-22 17:24:44 +03001500 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1501 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001502
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001503failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001504 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001505 return err;
1506}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001507
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001508void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001509{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001510 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001511
Marcel Holtmann181d6952020-05-06 09:57:47 +02001512 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001513
1514 hci_dev_lock(hdev);
1515
Johan Hedberg333ae952015-03-17 13:48:47 +02001516 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001517 if (!cmd)
1518 goto unlock;
1519
Johan Hedberg37438c12013-10-14 16:20:05 +03001520 if (status) {
1521 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001522 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001523 goto remove_cmd;
1524 }
1525
Johan Hedberg2b76f452013-03-15 17:07:04 -05001526 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001527 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001528
Johan Hedberg37438c12013-10-14 16:20:05 +03001529remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001530 mgmt_pending_remove(cmd);
1531
1532unlock:
1533 hci_dev_unlock(hdev);
1534}
1535
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001536static int set_connectable_update_settings(struct hci_dev *hdev,
1537 struct sock *sk, u8 val)
1538{
1539 bool changed = false;
1540 int err;
1541
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001542 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001543 changed = true;
1544
1545 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001546 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001547 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001548 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1549 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001550 }
1551
1552 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1553 if (err < 0)
1554 return err;
1555
Johan Hedberg562064e2014-07-08 16:35:34 +03001556 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001557 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001558 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001559 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001560 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001561
1562 return 0;
1563}
1564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001565static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001566 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001567{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001568 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001569 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001570 int err;
1571
Marcel Holtmann181d6952020-05-06 09:57:47 +02001572 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001573
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001574 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1575 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001576 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1577 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001578
Johan Hedberga7e80f22013-01-09 16:05:19 +02001579 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001580 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1581 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001582
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001584
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001585 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001586 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001587 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001588 }
1589
Johan Hedberg333ae952015-03-17 13:48:47 +02001590 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1591 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001592 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1593 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001594 goto failed;
1595 }
1596
Johan Hedberg73f22f62010-12-29 16:00:25 +02001597 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1598 if (!cmd) {
1599 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001600 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001601 }
1602
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001603 if (cp->val) {
1604 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1605 } else {
1606 if (hdev->discov_timeout > 0)
1607 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001608
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001609 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1610 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1611 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001612 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001613
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001614 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1615 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001616
1617failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001618 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001619 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001620}
1621
Johan Hedbergb2939472014-07-30 09:22:23 +03001622static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001623 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001624{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001625 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001626 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001627 int err;
1628
Marcel Holtmann181d6952020-05-06 09:57:47 +02001629 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001630
Johan Hedberga7e80f22013-01-09 16:05:19 +02001631 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001632 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001636
1637 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001638 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001639 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001640 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001641
Johan Hedbergb2939472014-07-30 09:22:23 +03001642 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001643 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001644 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001645
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001646 if (changed) {
1647 /* In limited privacy mode the change of bondable mode
1648 * may affect the local advertising address.
1649 */
1650 if (hdev_is_powered(hdev) &&
1651 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1652 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1653 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1654 queue_work(hdev->req_workqueue,
1655 &hdev->discoverable_update);
1656
Marcel Holtmann55594352013-10-06 16:11:57 -07001657 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001658 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001659
Marcel Holtmann55594352013-10-06 16:11:57 -07001660unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001661 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001662 return err;
1663}
1664
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001665static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1666 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001667{
1668 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001669 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001670 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001671 int err;
1672
Marcel Holtmann181d6952020-05-06 09:57:47 +02001673 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001674
Johan Hedberge6fe7982013-10-02 15:45:22 +03001675 status = mgmt_bredr_support(hdev);
1676 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1678 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001679
Johan Hedberga7e80f22013-01-09 16:05:19 +02001680 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001681 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001683
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001684 hci_dev_lock(hdev);
1685
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001686 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001687 bool changed = false;
1688
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001689 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001690 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001691 changed = true;
1692 }
1693
1694 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1695 if (err < 0)
1696 goto failed;
1697
1698 if (changed)
1699 err = new_settings(hdev, sk);
1700
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001701 goto failed;
1702 }
1703
Johan Hedberg333ae952015-03-17 13:48:47 +02001704 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001705 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1706 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001707 goto failed;
1708 }
1709
1710 val = !!cp->val;
1711
1712 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1713 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1714 goto failed;
1715 }
1716
1717 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1718 if (!cmd) {
1719 err = -ENOMEM;
1720 goto failed;
1721 }
1722
1723 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1724 if (err < 0) {
1725 mgmt_pending_remove(cmd);
1726 goto failed;
1727 }
1728
1729failed:
1730 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001731 return err;
1732}
1733
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001735{
1736 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001737 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001738 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001739 int err;
1740
Marcel Holtmann181d6952020-05-06 09:57:47 +02001741 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001742
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001743 status = mgmt_bredr_support(hdev);
1744 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001745 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001746
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001747 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1749 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001750
Johan Hedberga7e80f22013-01-09 16:05:19 +02001751 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001752 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001754
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001755 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001756
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001757 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001758 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001759
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001760 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001761 changed = !hci_dev_test_and_set_flag(hdev,
1762 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001763 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001764 changed = hci_dev_test_and_clear_flag(hdev,
1765 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001766 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001767 changed = hci_dev_test_and_clear_flag(hdev,
1768 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001769 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001770 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001771 }
1772
1773 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1774 if (err < 0)
1775 goto failed;
1776
1777 if (changed)
1778 err = new_settings(hdev, sk);
1779
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001780 goto failed;
1781 }
1782
Johan Hedberg333ae952015-03-17 13:48:47 +02001783 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001784 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1785 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001786 goto failed;
1787 }
1788
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001789 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001790 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1791 goto failed;
1792 }
1793
1794 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1795 if (!cmd) {
1796 err = -ENOMEM;
1797 goto failed;
1798 }
1799
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001800 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001801 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1802 sizeof(cp->val), &cp->val);
1803
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001804 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001805 if (err < 0) {
1806 mgmt_pending_remove(cmd);
1807 goto failed;
1808 }
1809
1810failed:
1811 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001812 return err;
1813}
1814
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001815static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001816{
1817 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001818 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001819 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001820 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001821
Marcel Holtmann181d6952020-05-06 09:57:47 +02001822 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001823
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -07001824 if (!IS_ENABLED(CONFIG_BT_HS))
1825 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1826 MGMT_STATUS_NOT_SUPPORTED);
1827
Johan Hedberge6fe7982013-10-02 15:45:22 +03001828 status = mgmt_bredr_support(hdev);
1829 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001830 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001831
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001832 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001833 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1834 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001835
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001836 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001837 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1838 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001839
Johan Hedberga7e80f22013-01-09 16:05:19 +02001840 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001841 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1842 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001843
Marcel Holtmannee392692013-10-01 22:59:23 -07001844 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001845
Johan Hedberg333ae952015-03-17 13:48:47 +02001846 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001847 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1848 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001849 goto unlock;
1850 }
1851
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001852 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001853 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001854 } else {
1855 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001856 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1857 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001858 goto unlock;
1859 }
1860
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001861 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001862 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001863
1864 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1865 if (err < 0)
1866 goto unlock;
1867
1868 if (changed)
1869 err = new_settings(hdev, sk);
1870
1871unlock:
1872 hci_dev_unlock(hdev);
1873 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001874}
1875
Marcel Holtmann1904a852015-01-11 13:50:44 -08001876static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001877{
1878 struct cmd_lookup match = { NULL, hdev };
1879
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301880 hci_dev_lock(hdev);
1881
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001882 if (status) {
1883 u8 mgmt_err = mgmt_status(status);
1884
1885 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1886 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301887 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001888 }
1889
1890 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1891
1892 new_settings(hdev, match.sk);
1893
1894 if (match.sk)
1895 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001896
1897 /* Make sure the controller has a good default for
1898 * advertising data. Restrict the update to when LE
1899 * has actually been enabled. During power on, the
1900 * update in powered_update_hci will take care of it.
1901 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001902 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001903 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001904 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301905 if (ext_adv_capable(hdev)) {
1906 int err;
1907
1908 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1909 if (!err)
1910 __hci_req_update_scan_rsp_data(&req, 0x00);
1911 } else {
1912 __hci_req_update_adv_data(&req, 0x00);
1913 __hci_req_update_scan_rsp_data(&req, 0x00);
1914 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001915 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001916 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001917 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301918
1919unlock:
1920 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001921}
1922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001924{
1925 struct mgmt_mode *cp = data;
1926 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001927 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001928 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001930 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001931
Marcel Holtmann181d6952020-05-06 09:57:47 +02001932 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001933
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001934 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001935 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1936 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001937
Johan Hedberga7e80f22013-01-09 16:05:19 +02001938 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001939 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1940 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001941
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001942 /* Bluetooth single mode LE only controllers or dual-mode
1943 * controllers configured as LE only devices, do not allow
1944 * switching LE off. These have either LE enabled explicitly
1945 * or BR/EDR has been previously switched off.
1946 *
1947 * When trying to enable an already enabled LE, then gracefully
1948 * send a positive response. Trying to disable it however will
1949 * result into rejection.
1950 */
1951 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1952 if (cp->val == 0x01)
1953 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1954
Johan Hedberga69e8372015-03-06 21:08:53 +02001955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1956 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001957 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001958
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001959 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001960
1961 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001962 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001963
Florian Grandel847818d2015-06-18 03:16:46 +02001964 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001965 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001966
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001967 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001968 bool changed = false;
1969
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001970 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001971 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001972 changed = true;
1973 }
1974
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001975 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001976 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001977 changed = true;
1978 }
1979
Johan Hedberg06199cf2012-02-22 16:37:11 +02001980 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1981 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001982 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001983
1984 if (changed)
1985 err = new_settings(hdev, sk);
1986
Johan Hedberg1de028c2012-02-29 19:55:35 -08001987 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001988 }
1989
Johan Hedberg333ae952015-03-17 13:48:47 +02001990 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1991 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001992 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1993 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001994 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001995 }
1996
1997 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1998 if (!cmd) {
1999 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002000 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002001 }
2002
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002003 hci_req_init(&req, hdev);
2004
Johan Hedberg06199cf2012-02-22 16:37:11 +02002005 memset(&hci_cp, 0, sizeof(hci_cp));
2006
2007 if (val) {
2008 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002009 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002010 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002011 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002012 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05302013
2014 if (ext_adv_capable(hdev))
2015 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002016 }
2017
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002018 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2019 &hci_cp);
2020
2021 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302022 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002023 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002024
Johan Hedberg1de028c2012-02-29 19:55:35 -08002025unlock:
2026 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002027 return err;
2028}
2029
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002030/* This is a helper function to test for pending mgmt commands that can
2031 * cause CoD or EIR HCI commands. We can only allow one such pending
2032 * mgmt command at a time since otherwise we cannot easily track what
2033 * the current values are, will be, and based on that calculate if a new
2034 * HCI command needs to be sent and if yes with what value.
2035 */
2036static bool pending_eir_or_class(struct hci_dev *hdev)
2037{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002038 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002039
2040 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2041 switch (cmd->opcode) {
2042 case MGMT_OP_ADD_UUID:
2043 case MGMT_OP_REMOVE_UUID:
2044 case MGMT_OP_SET_DEV_CLASS:
2045 case MGMT_OP_SET_POWERED:
2046 return true;
2047 }
2048 }
2049
2050 return false;
2051}
2052
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002053static const u8 bluetooth_base_uuid[] = {
2054 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2055 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2056};
2057
2058static u8 get_uuid_size(const u8 *uuid)
2059{
2060 u32 val;
2061
2062 if (memcmp(uuid, bluetooth_base_uuid, 12))
2063 return 128;
2064
2065 val = get_unaligned_le32(&uuid[12]);
2066 if (val > 0xffff)
2067 return 32;
2068
2069 return 16;
2070}
2071
Johan Hedberg92da6092013-03-15 17:06:55 -05002072static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2073{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002074 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002075
2076 hci_dev_lock(hdev);
2077
Johan Hedberg333ae952015-03-17 13:48:47 +02002078 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002079 if (!cmd)
2080 goto unlock;
2081
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002082 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2083 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002084
2085 mgmt_pending_remove(cmd);
2086
2087unlock:
2088 hci_dev_unlock(hdev);
2089}
2090
Marcel Holtmann1904a852015-01-11 13:50:44 -08002091static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002092{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002093 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002094
2095 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2096}
2097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002100 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002101 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002102 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002103 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002104 int err;
2105
Marcel Holtmann181d6952020-05-06 09:57:47 +02002106 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002108 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002109
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002110 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002111 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2112 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002113 goto failed;
2114 }
2115
Andre Guedes92c4c202012-06-07 19:05:44 -03002116 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117 if (!uuid) {
2118 err = -ENOMEM;
2119 goto failed;
2120 }
2121
2122 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002123 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002124 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125
Johan Hedbergde66aa62013-01-27 00:31:27 +02002126 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127
Johan Hedberg890ea892013-03-15 17:06:52 -05002128 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002129
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002130 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002131 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002132
Johan Hedberg92da6092013-03-15 17:06:55 -05002133 err = hci_req_run(&req, add_uuid_complete);
2134 if (err < 0) {
2135 if (err != -ENODATA)
2136 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002137
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002138 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2139 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002140 goto failed;
2141 }
2142
2143 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002144 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002145 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002146 goto failed;
2147 }
2148
2149 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002150
2151failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002153 return err;
2154}
2155
Johan Hedberg24b78d02012-02-23 23:24:30 +02002156static bool enable_service_cache(struct hci_dev *hdev)
2157{
2158 if (!hdev_is_powered(hdev))
2159 return false;
2160
Marcel Holtmann238be782015-03-13 02:11:06 -07002161 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002162 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2163 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002164 return true;
2165 }
2166
2167 return false;
2168}
2169
Marcel Holtmann1904a852015-01-11 13:50:44 -08002170static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002171{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002172 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002173
2174 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2175}
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002179{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002180 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002181 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002182 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002183 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05002184 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002185 int err, found;
2186
Marcel Holtmann181d6952020-05-06 09:57:47 +02002187 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002189 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002190
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002191 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002192 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2193 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002194 goto unlock;
2195 }
2196
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002197 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002198 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002199
Johan Hedberg24b78d02012-02-23 23:24:30 +02002200 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002201 err = mgmt_cmd_complete(sk, hdev->id,
2202 MGMT_OP_REMOVE_UUID,
2203 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002204 goto unlock;
2205 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002206
Johan Hedberg9246a862012-02-23 21:33:16 +02002207 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002208 }
2209
2210 found = 0;
2211
Johan Hedberg056341c2013-01-27 00:31:30 +02002212 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002213 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2214 continue;
2215
2216 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002217 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002218 found++;
2219 }
2220
2221 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002222 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2223 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002224 goto unlock;
2225 }
2226
Johan Hedberg9246a862012-02-23 21:33:16 +02002227update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002228 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002229
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002230 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002231 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002232
Johan Hedberg92da6092013-03-15 17:06:55 -05002233 err = hci_req_run(&req, remove_uuid_complete);
2234 if (err < 0) {
2235 if (err != -ENODATA)
2236 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002237
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002238 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2239 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002240 goto unlock;
2241 }
2242
2243 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002244 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002245 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 goto unlock;
2247 }
2248
2249 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002250
2251unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002252 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002253 return err;
2254}
2255
Marcel Holtmann1904a852015-01-11 13:50:44 -08002256static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002257{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002258 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002259
2260 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2261}
2262
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002263static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002264 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002265{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002266 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002267 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002268 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002269 int err;
2270
Marcel Holtmann181d6952020-05-06 09:57:47 +02002271 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002272
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002273 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002274 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2275 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002276
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002277 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002278
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002279 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002280 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2281 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002282 goto unlock;
2283 }
2284
2285 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002286 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2287 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002288 goto unlock;
2289 }
2290
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002291 hdev->major_class = cp->major;
2292 hdev->minor_class = cp->minor;
2293
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002294 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002295 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2296 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002297 goto unlock;
2298 }
2299
Johan Hedberg890ea892013-03-15 17:06:52 -05002300 hci_req_init(&req, hdev);
2301
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002302 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002303 hci_dev_unlock(hdev);
2304 cancel_delayed_work_sync(&hdev->service_cache);
2305 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002306 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002307 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002308
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002309 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002310
Johan Hedberg92da6092013-03-15 17:06:55 -05002311 err = hci_req_run(&req, set_class_complete);
2312 if (err < 0) {
2313 if (err != -ENODATA)
2314 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002315
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002316 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2317 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002318 goto unlock;
2319 }
2320
2321 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002322 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002323 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002324 goto unlock;
2325 }
2326
2327 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002328
Johan Hedbergb5235a62012-02-21 14:32:24 +02002329unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002330 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002331 return err;
2332}
2333
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002334static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002335 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002336{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002337 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002338 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2339 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002340 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002341 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002343
Marcel Holtmann181d6952020-05-06 09:57:47 +02002344 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002345
2346 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002347 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2348 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002349
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002350 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002351 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002352 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2353 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002354 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2355 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002356 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002357
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002358 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002359 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002360 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2361 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002362 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2363 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364 }
2365
Johan Hedberg4ae14302013-01-20 14:27:13 +02002366 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002367 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2368 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002369
Marcel Holtmann181d6952020-05-06 09:57:47 +02002370 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2371 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002372
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002373 for (i = 0; i < key_count; i++) {
2374 struct mgmt_link_key_info *key = &cp->keys[i];
2375
Marcel Holtmann8e991132014-01-10 02:07:25 -08002376 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002377 return mgmt_cmd_status(sk, hdev->id,
2378 MGMT_OP_LOAD_LINK_KEYS,
2379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002380 }
2381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002382 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383
2384 hci_link_keys_clear(hdev);
2385
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002386 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002387 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002388 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002389 changed = hci_dev_test_and_clear_flag(hdev,
2390 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002391
2392 if (changed)
2393 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002394
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002395 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002396 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002397
Alain Michaud600a8742020-01-07 00:43:17 +00002398 if (hci_is_blocked_key(hdev,
2399 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2400 key->val)) {
2401 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2402 &key->addr.bdaddr);
2403 continue;
2404 }
2405
Johan Hedberg58e92932014-06-24 14:00:26 +03002406 /* Always ignore debug keys and require a new pairing if
2407 * the user wants to use them.
2408 */
2409 if (key->type == HCI_LK_DEBUG_COMBINATION)
2410 continue;
2411
Johan Hedberg7652ff62014-06-24 13:15:49 +03002412 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2413 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002414 }
2415
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002416 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002417
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002418 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002419
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002420 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002421}
2422
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002423static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002425{
2426 struct mgmt_ev_device_unpaired ev;
2427
2428 bacpy(&ev.addr.bdaddr, bdaddr);
2429 ev.addr.type = addr_type;
2430
2431 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002432 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002433}
2434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002435static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002436 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002437{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002438 struct mgmt_cp_unpair_device *cp = data;
2439 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002440 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002441 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002442 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002443 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 int err;
2445
Johan Hedberga8a1d192011-11-10 15:54:38 +02002446 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002447 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2448 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002449
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002450 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002451 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2452 MGMT_STATUS_INVALID_PARAMS,
2453 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002454
Johan Hedberg118da702013-01-20 14:27:20 +02002455 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002456 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2457 MGMT_STATUS_INVALID_PARAMS,
2458 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002459
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002460 hci_dev_lock(hdev);
2461
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002462 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002463 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2464 MGMT_STATUS_NOT_POWERED, &rp,
2465 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002466 goto unlock;
2467 }
2468
Johan Hedberge0b2b272014-02-18 17:14:31 +02002469 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002470 /* If disconnection is requested, then look up the
2471 * connection. If the remote device is connected, it
2472 * will be later used to terminate the link.
2473 *
2474 * Setting it to NULL explicitly will cause no
2475 * termination of the link.
2476 */
2477 if (cp->disconnect)
2478 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2479 &cp->addr.bdaddr);
2480 else
2481 conn = NULL;
2482
Johan Hedberg124f6e32012-02-09 13:50:12 +02002483 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002484 if (err < 0) {
2485 err = mgmt_cmd_complete(sk, hdev->id,
2486 MGMT_OP_UNPAIR_DEVICE,
2487 MGMT_STATUS_NOT_PAIRED, &rp,
2488 sizeof(rp));
2489 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002490 }
2491
Johan Hedbergec182f02015-10-21 18:03:03 +03002492 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002493 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002494
Johan Hedbergec182f02015-10-21 18:03:03 +03002495 /* LE address type */
2496 addr_type = le_addr_type(cp->addr.type);
2497
Matias Karhumaacb28c302018-09-26 09:13:46 +03002498 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2499 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002500 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002501 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2502 MGMT_STATUS_NOT_PAIRED, &rp,
2503 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002504 goto unlock;
2505 }
2506
Johan Hedbergec182f02015-10-21 18:03:03 +03002507 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2508 if (!conn) {
2509 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2510 goto done;
2511 }
2512
Johan Hedbergc81d5552015-10-22 09:38:35 +03002513
Johan Hedbergec182f02015-10-21 18:03:03 +03002514 /* Defer clearing up the connection parameters until closing to
2515 * give a chance of keeping them if a repairing happens.
2516 */
2517 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2518
Johan Hedbergfc643612015-10-22 09:38:31 +03002519 /* Disable auto-connection parameters if present */
2520 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2521 if (params) {
2522 if (params->explicit_connect)
2523 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2524 else
2525 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2526 }
2527
Johan Hedbergec182f02015-10-21 18:03:03 +03002528 /* If disconnection is not requested, then clear the connection
2529 * variable so that the link is not terminated.
2530 */
2531 if (!cp->disconnect)
2532 conn = NULL;
2533
2534done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002535 /* If the connection variable is set, then termination of the
2536 * link is requested.
2537 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002538 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002539 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2540 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002541 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002542 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002543 }
2544
Johan Hedberg124f6e32012-02-09 13:50:12 +02002545 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002547 if (!cmd) {
2548 err = -ENOMEM;
2549 goto unlock;
2550 }
2551
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002552 cmd->cmd_complete = addr_cmd_complete;
2553
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002554 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002555 if (err < 0)
2556 mgmt_pending_remove(cmd);
2557
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002558unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002560 return err;
2561}
2562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002563static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002566 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002567 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002568 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002569 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570 int err;
2571
Marcel Holtmann181d6952020-05-06 09:57:47 +02002572 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002573
Johan Hedberg06a63b12013-01-20 14:27:21 +02002574 memset(&rp, 0, sizeof(rp));
2575 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2576 rp.addr.type = cp->addr.type;
2577
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002578 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002579 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2580 MGMT_STATUS_INVALID_PARAMS,
2581 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002582
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002584
2585 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002586 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2587 MGMT_STATUS_NOT_POWERED, &rp,
2588 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002589 goto failed;
2590 }
2591
Johan Hedberg333ae952015-03-17 13:48:47 +02002592 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002593 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2594 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002595 goto failed;
2596 }
2597
Andre Guedes591f47f2012-04-24 21:02:49 -03002598 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002599 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2600 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002601 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002602 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2603 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002604
Vishal Agarwalf9607272012-06-13 05:32:43 +05302605 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002606 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2607 MGMT_STATUS_NOT_CONNECTED, &rp,
2608 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002609 goto failed;
2610 }
2611
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002612 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002613 if (!cmd) {
2614 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002615 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002616 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002617
Johan Hedbergf5818c22014-12-05 13:36:02 +02002618 cmd->cmd_complete = generic_cmd_complete;
2619
Johan Hedberge3f2f922014-08-18 20:33:33 +03002620 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002621 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002622 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002623
2624failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002625 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002626 return err;
2627}
2628
Andre Guedes57c14772012-04-24 21:02:50 -03002629static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002630{
2631 switch (link_type) {
2632 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002633 switch (addr_type) {
2634 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002635 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002636
Johan Hedberg48264f02011-11-09 13:58:58 +02002637 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002638 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002639 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002640 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002641
Johan Hedberg4c659c32011-11-07 23:13:39 +02002642 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002643 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002644 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002645 }
2646}
2647
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002648static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2649 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002650{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002651 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002652 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002653 int err;
2654 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002655
Marcel Holtmann181d6952020-05-06 09:57:47 +02002656 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002658 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002659
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002660 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002661 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2662 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002663 goto unlock;
2664 }
2665
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002666 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002667 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2668 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002669 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002670 }
2671
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002672 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002673 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002674 err = -ENOMEM;
2675 goto unlock;
2676 }
2677
Johan Hedberg2784eb42011-01-21 13:56:35 +02002678 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002679 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002680 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2681 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002682 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002683 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002684 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002685 continue;
2686 i++;
2687 }
2688
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002689 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002690
Johan Hedberg4c659c32011-11-07 23:13:39 +02002691 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002692 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002693 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002694
Johan Hedberga38528f2011-01-22 06:46:43 +02002695 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002696
2697unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002698 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002699 return err;
2700}
2701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002702static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002704{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002705 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002706 int err;
2707
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002709 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002710 if (!cmd)
2711 return -ENOMEM;
2712
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002713 cmd->cmd_complete = addr_cmd_complete;
2714
Johan Hedbergd8457692012-02-17 14:24:57 +02002715 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002717 if (err < 0)
2718 mgmt_pending_remove(cmd);
2719
2720 return err;
2721}
2722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002726 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002727 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002729 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730 int err;
2731
Marcel Holtmann181d6952020-05-06 09:57:47 +02002732 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002733
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002734 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002735
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002736 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002737 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2738 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002739 goto failed;
2740 }
2741
Johan Hedbergd8457692012-02-17 14:24:57 +02002742 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002743 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2745 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002746 goto failed;
2747 }
2748
2749 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002750 struct mgmt_cp_pin_code_neg_reply ncp;
2751
2752 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002753
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002754 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002756 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002757 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002758 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2759 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002760
2761 goto failed;
2762 }
2763
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002764 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002765 if (!cmd) {
2766 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002767 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002768 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002769
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002770 cmd->cmd_complete = addr_cmd_complete;
2771
Johan Hedbergd8457692012-02-17 14:24:57 +02002772 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002773 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002774 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002775
2776 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2777 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002778 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002779
2780failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002782 return err;
2783}
2784
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2786 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002787{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002788 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002789
Marcel Holtmann181d6952020-05-06 09:57:47 +02002790 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002791
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002792 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002793 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002796 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002797
2798 hdev->io_capability = cp->io_capability;
2799
Marcel Holtmann181d6952020-05-06 09:57:47 +02002800 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002802 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002803
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002804 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2805 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002806}
2807
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002808static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002809{
2810 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002811 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002812
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002813 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002814 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2815 continue;
2816
Johan Hedberge9a416b2011-02-19 12:05:56 -03002817 if (cmd->user_data != conn)
2818 continue;
2819
2820 return cmd;
2821 }
2822
2823 return NULL;
2824}
2825
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002826static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002827{
2828 struct mgmt_rp_pair_device rp;
2829 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002830 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002831
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002832 bacpy(&rp.addr.bdaddr, &conn->dst);
2833 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002834
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002835 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2836 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002837
2838 /* So we don't get further callbacks for this connection */
2839 conn->connect_cfm_cb = NULL;
2840 conn->security_cfm_cb = NULL;
2841 conn->disconn_cfm_cb = NULL;
2842
David Herrmann76a68ba2013-04-06 20:28:37 +02002843 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002844
2845 /* The device is paired so there is no need to remove
2846 * its connection parameters anymore.
2847 */
2848 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002849
2850 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002851
2852 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853}
2854
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002855void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2856{
2857 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002858 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002859
2860 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002861 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002862 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002863 mgmt_pending_remove(cmd);
2864 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002865}
2866
Johan Hedberge9a416b2011-02-19 12:05:56 -03002867static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2868{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002869 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002870
2871 BT_DBG("status %u", status);
2872
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002873 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002874 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002875 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002876 return;
2877 }
2878
2879 cmd->cmd_complete(cmd, mgmt_status(status));
2880 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002881}
2882
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002883static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302884{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002885 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302886
2887 BT_DBG("status %u", status);
2888
2889 if (!status)
2890 return;
2891
2892 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002893 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302894 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002895 return;
2896 }
2897
2898 cmd->cmd_complete(cmd, mgmt_status(status));
2899 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302900}
2901
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002902static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002903 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002904{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002905 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002906 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002907 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002908 u8 sec_level, auth_type;
2909 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002910 int err;
2911
Marcel Holtmann181d6952020-05-06 09:57:47 +02002912 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002913
Szymon Jancf950a30e2013-01-18 12:48:07 +01002914 memset(&rp, 0, sizeof(rp));
2915 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2916 rp.addr.type = cp->addr.type;
2917
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002918 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002919 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2920 MGMT_STATUS_INVALID_PARAMS,
2921 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002922
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002923 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002924 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2925 MGMT_STATUS_INVALID_PARAMS,
2926 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002928 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002929
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002930 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002931 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2932 MGMT_STATUS_NOT_POWERED, &rp,
2933 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002934 goto unlock;
2935 }
2936
Johan Hedberg55e76b32015-03-10 22:34:40 +02002937 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2938 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2939 MGMT_STATUS_ALREADY_PAIRED, &rp,
2940 sizeof(rp));
2941 goto unlock;
2942 }
2943
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002944 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002945 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002946
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002947 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002948 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002949 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002950 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002951 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002952 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002953
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002954 /* When pairing a new device, it is expected to remember
2955 * this device for future connections. Adding the connection
2956 * parameter information ahead of time allows tracking
2957 * of the slave preferred values and will speed up any
2958 * further connection establishment.
2959 *
2960 * If connection parameters already exist, then they
2961 * will be kept and this function does nothing.
2962 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002963 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2964
2965 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2966 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002967
Manish Mandlik76b13992020-06-17 16:39:19 +02002968 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2969 sec_level, HCI_LE_CONN_TIMEOUT,
2970 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002971 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002972
Ville Tervo30e76272011-02-22 16:10:53 -03002973 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002974 int status;
2975
2976 if (PTR_ERR(conn) == -EBUSY)
2977 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002978 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2979 status = MGMT_STATUS_NOT_SUPPORTED;
2980 else if (PTR_ERR(conn) == -ECONNREFUSED)
2981 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002982 else
2983 status = MGMT_STATUS_CONNECT_FAILED;
2984
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002985 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2986 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002987 goto unlock;
2988 }
2989
2990 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002991 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002992 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2993 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002994 goto unlock;
2995 }
2996
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002997 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002998 if (!cmd) {
2999 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003000 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003001 goto unlock;
3002 }
3003
Johan Hedberg04ab2742014-12-05 13:36:04 +02003004 cmd->cmd_complete = pairing_complete;
3005
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003006 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003007 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003008 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003009 conn->security_cfm_cb = pairing_complete_cb;
3010 conn->disconn_cfm_cb = pairing_complete_cb;
3011 } else {
3012 conn->connect_cfm_cb = le_pairing_complete_cb;
3013 conn->security_cfm_cb = le_pairing_complete_cb;
3014 conn->disconn_cfm_cb = le_pairing_complete_cb;
3015 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003016
Johan Hedberge9a416b2011-02-19 12:05:56 -03003017 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003018 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003019
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003020 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003021 hci_conn_security(conn, sec_level, auth_type, true)) {
3022 cmd->cmd_complete(cmd, 0);
3023 mgmt_pending_remove(cmd);
3024 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003025
3026 err = 0;
3027
3028unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003029 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003030 return err;
3031}
3032
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003033static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3034 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003035{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003036 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003037 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003038 struct hci_conn *conn;
3039 int err;
3040
Marcel Holtmann181d6952020-05-06 09:57:47 +02003041 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003042
Johan Hedberg28424702012-02-02 04:02:29 +02003043 hci_dev_lock(hdev);
3044
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003045 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003046 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3047 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003048 goto unlock;
3049 }
3050
Johan Hedberg333ae952015-03-17 13:48:47 +02003051 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003052 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003053 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3054 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003055 goto unlock;
3056 }
3057
3058 conn = cmd->user_data;
3059
3060 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003061 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3062 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003063 goto unlock;
3064 }
3065
Johan Hedberga511b352014-12-11 21:45:45 +02003066 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3067 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003068
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003069 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3070 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003071
3072 /* Since user doesn't want to proceed with the connection, abort any
3073 * ongoing pairing and then terminate the link if it was created
3074 * because of the pair device action.
3075 */
3076 if (addr->type == BDADDR_BREDR)
3077 hci_remove_link_key(hdev, &addr->bdaddr);
3078 else
3079 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3080 le_addr_type(addr->type));
3081
3082 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3083 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3084
Johan Hedberg28424702012-02-02 04:02:29 +02003085unlock:
3086 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003087 return err;
3088}
3089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003090static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003091 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003093{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003094 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003095 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003096 int err;
3097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003098 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003099
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003100 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003101 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3102 MGMT_STATUS_NOT_POWERED, addr,
3103 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003104 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003105 }
3106
Johan Hedberg1707c602013-03-15 17:07:15 -05003107 if (addr->type == BDADDR_BREDR)
3108 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003109 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003110 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3111 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003112
Johan Hedberg272d90d2012-02-09 15:26:12 +02003113 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003114 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3115 MGMT_STATUS_NOT_CONNECTED, addr,
3116 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003117 goto done;
3118 }
3119
Johan Hedberg1707c602013-03-15 17:07:15 -05003120 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003121 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003122 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003123 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3124 MGMT_STATUS_SUCCESS, addr,
3125 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003126 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003127 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3128 MGMT_STATUS_FAILED, addr,
3129 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003130
Brian Gix47c15e22011-11-16 13:53:14 -08003131 goto done;
3132 }
3133
Johan Hedberg1707c602013-03-15 17:07:15 -05003134 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003135 if (!cmd) {
3136 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003137 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003138 }
3139
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003140 cmd->cmd_complete = addr_cmd_complete;
3141
Brian Gix0df4c182011-11-16 13:53:13 -08003142 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003143 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3144 struct hci_cp_user_passkey_reply cp;
3145
Johan Hedberg1707c602013-03-15 17:07:15 -05003146 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003147 cp.passkey = passkey;
3148 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3149 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003150 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3151 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003152
Johan Hedberga664b5b2011-02-19 12:06:02 -03003153 if (err < 0)
3154 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003155
Brian Gix0df4c182011-11-16 13:53:13 -08003156done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003157 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003158 return err;
3159}
3160
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303161static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3162 void *data, u16 len)
3163{
3164 struct mgmt_cp_pin_code_neg_reply *cp = data;
3165
Marcel Holtmann181d6952020-05-06 09:57:47 +02003166 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303167
Johan Hedberg1707c602013-03-15 17:07:15 -05003168 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303169 MGMT_OP_PIN_CODE_NEG_REPLY,
3170 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3171}
3172
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3174 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003175{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003176 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003177
Marcel Holtmann181d6952020-05-06 09:57:47 +02003178 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003179
3180 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003181 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3182 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003183
Johan Hedberg1707c602013-03-15 17:07:15 -05003184 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 MGMT_OP_USER_CONFIRM_REPLY,
3186 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003187}
3188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003189static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003190 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003191{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003192 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003193
Marcel Holtmann181d6952020-05-06 09:57:47 +02003194 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003195
Johan Hedberg1707c602013-03-15 17:07:15 -05003196 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3198 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003199}
3200
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3202 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003203{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003204 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003205
Marcel Holtmann181d6952020-05-06 09:57:47 +02003206 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003207
Johan Hedberg1707c602013-03-15 17:07:15 -05003208 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 MGMT_OP_USER_PASSKEY_REPLY,
3210 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003211}
3212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003213static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003214 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003215{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003216 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003217
Marcel Holtmann181d6952020-05-06 09:57:47 +02003218 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003219
Johan Hedberg1707c602013-03-15 17:07:15 -05003220 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003221 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3222 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003223}
3224
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003225static void adv_expire(struct hci_dev *hdev, u32 flags)
3226{
3227 struct adv_info *adv_instance;
3228 struct hci_request req;
3229 int err;
3230
3231 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3232 if (!adv_instance)
3233 return;
3234
3235 /* stop if current instance doesn't need to be changed */
3236 if (!(adv_instance->flags & flags))
3237 return;
3238
3239 cancel_adv_timeout(hdev);
3240
3241 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3242 if (!adv_instance)
3243 return;
3244
3245 hci_req_init(&req, hdev);
3246 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3247 true);
3248 if (err)
3249 return;
3250
3251 hci_req_run(&req, NULL);
3252}
3253
Marcel Holtmann1904a852015-01-11 13:50:44 -08003254static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003255{
3256 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003257 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003258
Marcel Holtmann181d6952020-05-06 09:57:47 +02003259 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003260
3261 hci_dev_lock(hdev);
3262
Johan Hedberg333ae952015-03-17 13:48:47 +02003263 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003264 if (!cmd)
3265 goto unlock;
3266
3267 cp = cmd->param;
3268
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003269 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003270 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3271 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003272 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003273 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3274 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003275
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003276 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3277 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3278 }
3279
Johan Hedberg13928972013-03-15 17:07:00 -05003280 mgmt_pending_remove(cmd);
3281
3282unlock:
3283 hci_dev_unlock(hdev);
3284}
3285
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003286static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003287 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003288{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003289 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003290 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003291 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003292 int err;
3293
Marcel Holtmann181d6952020-05-06 09:57:47 +02003294 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003295
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003296 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003297
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003298 /* If the old values are the same as the new ones just return a
3299 * direct command complete event.
3300 */
3301 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3302 !memcmp(hdev->short_name, cp->short_name,
3303 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003304 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3305 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003306 goto failed;
3307 }
3308
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003309 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003310
Johan Hedbergb5235a62012-02-21 14:32:24 +02003311 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003312 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003313
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003314 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3315 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003316 if (err < 0)
3317 goto failed;
3318
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003319 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3320 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003321 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003322
Johan Hedbergb5235a62012-02-21 14:32:24 +02003323 goto failed;
3324 }
3325
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003326 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003327 if (!cmd) {
3328 err = -ENOMEM;
3329 goto failed;
3330 }
3331
Johan Hedberg13928972013-03-15 17:07:00 -05003332 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3333
Johan Hedberg890ea892013-03-15 17:06:52 -05003334 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003335
3336 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003337 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003338 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003339 }
3340
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003341 /* The name is stored in the scan response data and so
3342 * no need to udpate the advertising data here.
3343 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003344 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003345 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003346
Johan Hedberg13928972013-03-15 17:07:00 -05003347 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003348 if (err < 0)
3349 mgmt_pending_remove(cmd);
3350
3351failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003352 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003353 return err;
3354}
3355
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003356static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3357 u16 len)
3358{
3359 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003360 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003361 int err;
3362
Marcel Holtmann181d6952020-05-06 09:57:47 +02003363 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003364
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003365 if (!lmp_le_capable(hdev))
3366 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3367 MGMT_STATUS_NOT_SUPPORTED);
3368
Alain Michaud6613bab2020-01-22 19:47:44 +00003369 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003370
3371 hci_dev_lock(hdev);
3372
Alain Michaud6613bab2020-01-22 19:47:44 +00003373 if (hdev->appearance != appearance) {
3374 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003375
3376 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3377 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003378
3379 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003380 }
3381
3382 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3383 0);
3384
3385 hci_dev_unlock(hdev);
3386
3387 return err;
3388}
3389
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303390static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3391 void *data, u16 len)
3392{
3393 struct mgmt_rp_get_phy_confguration rp;
3394
Marcel Holtmann181d6952020-05-06 09:57:47 +02003395 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303396
3397 hci_dev_lock(hdev);
3398
3399 memset(&rp, 0, sizeof(rp));
3400
3401 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3402 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3403 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3404
3405 hci_dev_unlock(hdev);
3406
3407 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3408 &rp, sizeof(rp));
3409}
3410
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303411int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3412{
3413 struct mgmt_ev_phy_configuration_changed ev;
3414
3415 memset(&ev, 0, sizeof(ev));
3416
3417 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3418
3419 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3420 sizeof(ev), skip);
3421}
3422
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303423static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3424 u16 opcode, struct sk_buff *skb)
3425{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303426 struct mgmt_pending_cmd *cmd;
3427
Marcel Holtmann181d6952020-05-06 09:57:47 +02003428 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303429
3430 hci_dev_lock(hdev);
3431
3432 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3433 if (!cmd)
3434 goto unlock;
3435
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303436 if (status) {
3437 mgmt_cmd_status(cmd->sk, hdev->id,
3438 MGMT_OP_SET_PHY_CONFIGURATION,
3439 mgmt_status(status));
3440 } else {
3441 mgmt_cmd_complete(cmd->sk, hdev->id,
3442 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3443 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303444
3445 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303446 }
3447
3448 mgmt_pending_remove(cmd);
3449
3450unlock:
3451 hci_dev_unlock(hdev);
3452}
3453
3454static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3455 void *data, u16 len)
3456{
3457 struct mgmt_cp_set_phy_confguration *cp = data;
3458 struct hci_cp_le_set_default_phy cp_phy;
3459 struct mgmt_pending_cmd *cmd;
3460 struct hci_request req;
3461 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3462 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303463 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303464 int err;
3465
Marcel Holtmann181d6952020-05-06 09:57:47 +02003466 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303467
3468 configurable_phys = get_configurable_phys(hdev);
3469 supported_phys = get_supported_phys(hdev);
3470 selected_phys = __le32_to_cpu(cp->selected_phys);
3471
3472 if (selected_phys & ~supported_phys)
3473 return mgmt_cmd_status(sk, hdev->id,
3474 MGMT_OP_SET_PHY_CONFIGURATION,
3475 MGMT_STATUS_INVALID_PARAMS);
3476
3477 unconfigure_phys = supported_phys & ~configurable_phys;
3478
3479 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3480 return mgmt_cmd_status(sk, hdev->id,
3481 MGMT_OP_SET_PHY_CONFIGURATION,
3482 MGMT_STATUS_INVALID_PARAMS);
3483
3484 if (selected_phys == get_selected_phys(hdev))
3485 return mgmt_cmd_complete(sk, hdev->id,
3486 MGMT_OP_SET_PHY_CONFIGURATION,
3487 0, NULL, 0);
3488
3489 hci_dev_lock(hdev);
3490
3491 if (!hdev_is_powered(hdev)) {
3492 err = mgmt_cmd_status(sk, hdev->id,
3493 MGMT_OP_SET_PHY_CONFIGURATION,
3494 MGMT_STATUS_REJECTED);
3495 goto unlock;
3496 }
3497
3498 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3499 err = mgmt_cmd_status(sk, hdev->id,
3500 MGMT_OP_SET_PHY_CONFIGURATION,
3501 MGMT_STATUS_BUSY);
3502 goto unlock;
3503 }
3504
3505 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3506 pkt_type |= (HCI_DH3 | HCI_DM3);
3507 else
3508 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3509
3510 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3511 pkt_type |= (HCI_DH5 | HCI_DM5);
3512 else
3513 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3514
3515 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3516 pkt_type &= ~HCI_2DH1;
3517 else
3518 pkt_type |= HCI_2DH1;
3519
3520 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3521 pkt_type &= ~HCI_2DH3;
3522 else
3523 pkt_type |= HCI_2DH3;
3524
3525 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3526 pkt_type &= ~HCI_2DH5;
3527 else
3528 pkt_type |= HCI_2DH5;
3529
3530 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3531 pkt_type &= ~HCI_3DH1;
3532 else
3533 pkt_type |= HCI_3DH1;
3534
3535 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3536 pkt_type &= ~HCI_3DH3;
3537 else
3538 pkt_type |= HCI_3DH3;
3539
3540 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3541 pkt_type &= ~HCI_3DH5;
3542 else
3543 pkt_type |= HCI_3DH5;
3544
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303545 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303546 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303547 changed = true;
3548 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303549
3550 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3551 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303552 if (changed)
3553 mgmt_phy_configuration_changed(hdev, sk);
3554
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303555 err = mgmt_cmd_complete(sk, hdev->id,
3556 MGMT_OP_SET_PHY_CONFIGURATION,
3557 0, NULL, 0);
3558
3559 goto unlock;
3560 }
3561
3562 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3563 len);
3564 if (!cmd) {
3565 err = -ENOMEM;
3566 goto unlock;
3567 }
3568
3569 hci_req_init(&req, hdev);
3570
3571 memset(&cp_phy, 0, sizeof(cp_phy));
3572
3573 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3574 cp_phy.all_phys |= 0x01;
3575
3576 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3577 cp_phy.all_phys |= 0x02;
3578
3579 if (selected_phys & MGMT_PHY_LE_1M_TX)
3580 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3581
3582 if (selected_phys & MGMT_PHY_LE_2M_TX)
3583 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3584
3585 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3586 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3587
3588 if (selected_phys & MGMT_PHY_LE_1M_RX)
3589 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3590
3591 if (selected_phys & MGMT_PHY_LE_2M_RX)
3592 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3593
3594 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3595 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3596
3597 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3598
3599 err = hci_req_run_skb(&req, set_default_phy_complete);
3600 if (err < 0)
3601 mgmt_pending_remove(cmd);
3602
3603unlock:
3604 hci_dev_unlock(hdev);
3605
3606 return err;
3607}
3608
Alain Michaud600a8742020-01-07 00:43:17 +00003609static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3610 u16 len)
3611{
3612 int err = MGMT_STATUS_SUCCESS;
3613 struct mgmt_cp_set_blocked_keys *keys = data;
3614 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3615 sizeof(struct mgmt_blocked_key_info));
3616 u16 key_count, expected_len;
3617 int i;
3618
Marcel Holtmann181d6952020-05-06 09:57:47 +02003619 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003620
3621 key_count = __le16_to_cpu(keys->key_count);
3622 if (key_count > max_key_count) {
3623 bt_dev_err(hdev, "too big key_count value %u", key_count);
3624 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3625 MGMT_STATUS_INVALID_PARAMS);
3626 }
3627
3628 expected_len = struct_size(keys, keys, key_count);
3629 if (expected_len != len) {
3630 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3631 expected_len, len);
3632 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3633 MGMT_STATUS_INVALID_PARAMS);
3634 }
3635
3636 hci_dev_lock(hdev);
3637
3638 hci_blocked_keys_clear(hdev);
3639
3640 for (i = 0; i < keys->key_count; ++i) {
3641 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3642
3643 if (!b) {
3644 err = MGMT_STATUS_NO_RESOURCES;
3645 break;
3646 }
3647
3648 b->type = keys->keys[i].type;
3649 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3650 list_add_rcu(&b->list, &hdev->blocked_keys);
3651 }
3652 hci_dev_unlock(hdev);
3653
3654 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3655 err, NULL, 0);
3656}
3657
Alain Michaud00bce3f2020-03-05 16:14:59 +00003658static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3659 void *data, u16 len)
3660{
3661 struct mgmt_mode *cp = data;
3662 int err;
3663 bool changed = false;
3664
Marcel Holtmann181d6952020-05-06 09:57:47 +02003665 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003666
3667 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3668 return mgmt_cmd_status(sk, hdev->id,
3669 MGMT_OP_SET_WIDEBAND_SPEECH,
3670 MGMT_STATUS_NOT_SUPPORTED);
3671
3672 if (cp->val != 0x00 && cp->val != 0x01)
3673 return mgmt_cmd_status(sk, hdev->id,
3674 MGMT_OP_SET_WIDEBAND_SPEECH,
3675 MGMT_STATUS_INVALID_PARAMS);
3676
3677 hci_dev_lock(hdev);
3678
3679 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3680 err = mgmt_cmd_status(sk, hdev->id,
3681 MGMT_OP_SET_WIDEBAND_SPEECH,
3682 MGMT_STATUS_BUSY);
3683 goto unlock;
3684 }
3685
3686 if (hdev_is_powered(hdev) &&
3687 !!cp->val != hci_dev_test_flag(hdev,
3688 HCI_WIDEBAND_SPEECH_ENABLED)) {
3689 err = mgmt_cmd_status(sk, hdev->id,
3690 MGMT_OP_SET_WIDEBAND_SPEECH,
3691 MGMT_STATUS_REJECTED);
3692 goto unlock;
3693 }
3694
3695 if (cp->val)
3696 changed = !hci_dev_test_and_set_flag(hdev,
3697 HCI_WIDEBAND_SPEECH_ENABLED);
3698 else
3699 changed = hci_dev_test_and_clear_flag(hdev,
3700 HCI_WIDEBAND_SPEECH_ENABLED);
3701
3702 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3703 if (err < 0)
3704 goto unlock;
3705
3706 if (changed)
3707 err = new_settings(hdev, sk);
3708
3709unlock:
3710 hci_dev_unlock(hdev);
3711 return err;
3712}
3713
Marcel Holtmannbc292252020-04-03 21:44:05 +02003714static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3715 void *data, u16 data_len)
3716{
3717 char buf[16];
3718 struct mgmt_rp_read_security_info *rp = (void *)buf;
3719 u16 sec_len = 0;
3720 u8 flags = 0;
3721
3722 bt_dev_dbg(hdev, "sock %p", sk);
3723
3724 memset(&buf, 0, sizeof(buf));
3725
3726 hci_dev_lock(hdev);
3727
3728 /* When the Read Simple Pairing Options command is supported, then
3729 * the remote public key validation is supported.
3730 */
3731 if (hdev->commands[41] & 0x08)
3732 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3733
3734 flags |= 0x02; /* Remote public key validation (LE) */
3735
3736 /* When the Read Encryption Key Size command is supported, then the
3737 * encryption key size is enforced.
3738 */
3739 if (hdev->commands[20] & 0x10)
3740 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3741
3742 flags |= 0x08; /* Encryption key size enforcement (LE) */
3743
3744 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3745
3746 /* When the Read Simple Pairing Options command is supported, then
3747 * also max encryption key size information is provided.
3748 */
3749 if (hdev->commands[41] & 0x08)
3750 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3751 hdev->max_enc_key_size);
3752
3753 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3754
3755 rp->sec_len = cpu_to_le16(sec_len);
3756
3757 hci_dev_unlock(hdev);
3758
3759 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3760 rp, sizeof(*rp) + sec_len);
3761}
3762
Marcel Holtmanne625e502020-05-06 09:57:52 +02003763#ifdef CONFIG_BT_FEATURE_DEBUG
3764/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3765static const u8 debug_uuid[16] = {
3766 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3767 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3768};
3769#endif
3770
Alain Michaud15d8ce02020-07-07 17:46:06 +02003771/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3772static const u8 simult_central_periph_uuid[16] = {
3773 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3774 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3775};
3776
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303777/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3778static const u8 rpa_resolution_uuid[16] = {
3779 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3780 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3781};
3782
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003783static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3784 void *data, u16 data_len)
3785{
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303786 char buf[62]; /* Enough space for 3 features */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003787 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3788 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003789 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003790
3791 bt_dev_dbg(hdev, "sock %p", sk);
3792
3793 memset(&buf, 0, sizeof(buf));
3794
Marcel Holtmanne625e502020-05-06 09:57:52 +02003795#ifdef CONFIG_BT_FEATURE_DEBUG
3796 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003797 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003798
3799 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3800 rp->features[idx].flags = cpu_to_le32(flags);
3801 idx++;
3802 }
3803#endif
3804
Alain Michaud15d8ce02020-07-07 17:46:06 +02003805 if (hdev) {
3806 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3807 (hdev->le_states[4] & 0x08) && /* Central */
3808 (hdev->le_states[4] & 0x40) && /* Peripheral */
3809 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3810 flags = BIT(0);
3811 else
3812 flags = 0;
3813
3814 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3815 rp->features[idx].flags = cpu_to_le32(flags);
3816 idx++;
3817 }
3818
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303819 if (hdev && use_ll_privacy(hdev)) {
3820 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3821 flags = BIT(0) | BIT(1);
3822 else
3823 flags = BIT(1);
3824
3825 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3826 rp->features[idx].flags = cpu_to_le32(flags);
3827 idx++;
3828 }
3829
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003830 rp->feature_count = cpu_to_le16(idx);
3831
3832 /* After reading the experimental features information, enable
3833 * the events to update client on any future change.
3834 */
3835 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3836
3837 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3838 MGMT_OP_READ_EXP_FEATURES_INFO,
3839 0, rp, sizeof(*rp) + (20 * idx));
3840}
3841
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303842static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3843 struct sock *skip)
3844{
3845 struct mgmt_ev_exp_feature_changed ev;
3846
3847 memset(&ev, 0, sizeof(ev));
3848 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3849 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3850
3851 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3852 &ev, sizeof(ev),
3853 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3854
3855}
3856
Marcel Holtmanne625e502020-05-06 09:57:52 +02003857#ifdef CONFIG_BT_FEATURE_DEBUG
3858static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3859{
3860 struct mgmt_ev_exp_feature_changed ev;
3861
3862 memset(&ev, 0, sizeof(ev));
3863 memcpy(ev.uuid, debug_uuid, 16);
3864 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3865
3866 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3867 &ev, sizeof(ev),
3868 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3869}
3870#endif
3871
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003872static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3873 void *data, u16 data_len)
3874{
3875 struct mgmt_cp_set_exp_feature *cp = data;
3876 struct mgmt_rp_set_exp_feature rp;
3877
3878 bt_dev_dbg(hdev, "sock %p", sk);
3879
3880 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3881 memset(rp.uuid, 0, 16);
3882 rp.flags = cpu_to_le32(0);
3883
Marcel Holtmanne625e502020-05-06 09:57:52 +02003884#ifdef CONFIG_BT_FEATURE_DEBUG
3885 if (!hdev) {
3886 bool changed = bt_dbg_get();
3887
3888 bt_dbg_set(false);
3889
3890 if (changed)
3891 exp_debug_feature_changed(false, sk);
3892 }
3893#endif
3894
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303895 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3896 bool changed = hci_dev_test_flag(hdev,
3897 HCI_ENABLE_LL_PRIVACY);
3898
3899 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3900
3901 if (changed)
3902 exp_ll_privacy_feature_changed(false, hdev, sk);
3903 }
3904
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003905 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3906
3907 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3908 MGMT_OP_SET_EXP_FEATURE, 0,
3909 &rp, sizeof(rp));
3910 }
3911
Marcel Holtmanne625e502020-05-06 09:57:52 +02003912#ifdef CONFIG_BT_FEATURE_DEBUG
3913 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3914 bool val, changed;
3915 int err;
3916
3917 /* Command requires to use the non-controller index */
3918 if (hdev)
3919 return mgmt_cmd_status(sk, hdev->id,
3920 MGMT_OP_SET_EXP_FEATURE,
3921 MGMT_STATUS_INVALID_INDEX);
3922
3923 /* Parameters are limited to a single octet */
3924 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3925 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3926 MGMT_OP_SET_EXP_FEATURE,
3927 MGMT_STATUS_INVALID_PARAMS);
3928
3929 /* Only boolean on/off is supported */
3930 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3931 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3932 MGMT_OP_SET_EXP_FEATURE,
3933 MGMT_STATUS_INVALID_PARAMS);
3934
3935 val = !!cp->param[0];
3936 changed = val ? !bt_dbg_get() : bt_dbg_get();
3937 bt_dbg_set(val);
3938
3939 memcpy(rp.uuid, debug_uuid, 16);
3940 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3941
3942 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3943
3944 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3945 MGMT_OP_SET_EXP_FEATURE, 0,
3946 &rp, sizeof(rp));
3947
3948 if (changed)
3949 exp_debug_feature_changed(val, sk);
3950
3951 return err;
3952 }
3953#endif
3954
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303955 if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
3956 bool val, changed;
3957 int err;
3958 u32 flags;
3959
3960 /* Command requires to use the controller index */
3961 if (!hdev)
3962 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3963 MGMT_OP_SET_EXP_FEATURE,
3964 MGMT_STATUS_INVALID_INDEX);
3965
3966 /* Changes can only be made when controller is powered down */
3967 if (hdev_is_powered(hdev))
3968 return mgmt_cmd_status(sk, hdev->id,
3969 MGMT_OP_SET_EXP_FEATURE,
3970 MGMT_STATUS_NOT_POWERED);
3971
3972 /* Parameters are limited to a single octet */
3973 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3974 return mgmt_cmd_status(sk, hdev->id,
3975 MGMT_OP_SET_EXP_FEATURE,
3976 MGMT_STATUS_INVALID_PARAMS);
3977
3978 /* Only boolean on/off is supported */
3979 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3980 return mgmt_cmd_status(sk, hdev->id,
3981 MGMT_OP_SET_EXP_FEATURE,
3982 MGMT_STATUS_INVALID_PARAMS);
3983
3984 val = !!cp->param[0];
3985
3986 if (val) {
3987 changed = !hci_dev_test_flag(hdev,
3988 HCI_ENABLE_LL_PRIVACY);
3989 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3990 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
3991
3992 /* Enable LL privacy + supported settings changed */
3993 flags = BIT(0) | BIT(1);
3994 } else {
3995 changed = hci_dev_test_flag(hdev,
3996 HCI_ENABLE_LL_PRIVACY);
3997 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3998
3999 /* Disable LL privacy + supported settings changed */
4000 flags = BIT(1);
4001 }
4002
4003 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4004 rp.flags = cpu_to_le32(flags);
4005
4006 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4007
4008 err = mgmt_cmd_complete(sk, hdev->id,
4009 MGMT_OP_SET_EXP_FEATURE, 0,
4010 &rp, sizeof(rp));
4011
4012 if (changed)
4013 exp_ll_privacy_feature_changed(val, hdev, sk);
4014
4015 return err;
4016 }
4017
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004018 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4019 MGMT_OP_SET_EXP_FEATURE,
4020 MGMT_STATUS_NOT_SUPPORTED);
4021}
4022
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004023#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4024
4025static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4026 u16 data_len)
4027{
4028 struct mgmt_cp_get_device_flags *cp = data;
4029 struct mgmt_rp_get_device_flags rp;
4030 struct bdaddr_list_with_flags *br_params;
4031 struct hci_conn_params *params;
4032 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4033 u32 current_flags = 0;
4034 u8 status = MGMT_STATUS_INVALID_PARAMS;
4035
4036 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4037 &cp->addr.bdaddr, cp->addr.type);
4038
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004039 hci_dev_lock(hdev);
4040
Tedd Ho-Jeong An8d7a3982021-05-26 10:36:22 -07004041 memset(&rp, 0, sizeof(rp));
4042
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004043 if (cp->addr.type == BDADDR_BREDR) {
4044 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4045 &cp->addr.bdaddr,
4046 cp->addr.type);
4047 if (!br_params)
4048 goto done;
4049
4050 current_flags = br_params->current_flags;
4051 } else {
4052 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4053 le_addr_type(cp->addr.type));
4054
4055 if (!params)
4056 goto done;
4057
4058 current_flags = params->current_flags;
4059 }
4060
4061 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4062 rp.addr.type = cp->addr.type;
4063 rp.supported_flags = cpu_to_le32(supported_flags);
4064 rp.current_flags = cpu_to_le32(current_flags);
4065
4066 status = MGMT_STATUS_SUCCESS;
4067
4068done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004069 hci_dev_unlock(hdev);
4070
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004071 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4072 &rp, sizeof(rp));
4073}
4074
4075static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4076 bdaddr_t *bdaddr, u8 bdaddr_type,
4077 u32 supported_flags, u32 current_flags)
4078{
4079 struct mgmt_ev_device_flags_changed ev;
4080
4081 bacpy(&ev.addr.bdaddr, bdaddr);
4082 ev.addr.type = bdaddr_type;
4083 ev.supported_flags = cpu_to_le32(supported_flags);
4084 ev.current_flags = cpu_to_le32(current_flags);
4085
4086 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4087}
4088
4089static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4090 u16 len)
4091{
4092 struct mgmt_cp_set_device_flags *cp = data;
4093 struct bdaddr_list_with_flags *br_params;
4094 struct hci_conn_params *params;
4095 u8 status = MGMT_STATUS_INVALID_PARAMS;
4096 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4097 u32 current_flags = __le32_to_cpu(cp->current_flags);
4098
4099 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4100 &cp->addr.bdaddr, cp->addr.type,
4101 __le32_to_cpu(current_flags));
4102
4103 if ((supported_flags | current_flags) != supported_flags) {
4104 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4105 current_flags, supported_flags);
4106 goto done;
4107 }
4108
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004109 hci_dev_lock(hdev);
4110
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004111 if (cp->addr.type == BDADDR_BREDR) {
4112 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4113 &cp->addr.bdaddr,
4114 cp->addr.type);
4115
4116 if (br_params) {
4117 br_params->current_flags = current_flags;
4118 status = MGMT_STATUS_SUCCESS;
4119 } else {
4120 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4121 &cp->addr.bdaddr, cp->addr.type);
4122 }
4123 } else {
4124 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4125 le_addr_type(cp->addr.type));
4126 if (params) {
4127 params->current_flags = current_flags;
4128 status = MGMT_STATUS_SUCCESS;
4129 } else {
4130 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4131 &cp->addr.bdaddr,
4132 le_addr_type(cp->addr.type));
4133 }
4134 }
4135
4136done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004137 hci_dev_unlock(hdev);
4138
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004139 if (status == MGMT_STATUS_SUCCESS)
4140 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4141 supported_flags, current_flags);
4142
4143 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4144 &cp->addr, sizeof(cp->addr));
4145}
4146
Miao-chen Choub52729f2020-06-17 16:39:16 +02004147static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4148 u16 handle)
4149{
4150 struct mgmt_ev_adv_monitor_added ev;
4151
4152 ev.monitor_handle = cpu_to_le16(handle);
4153
4154 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4155}
4156
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004157static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
4158 u16 handle)
4159{
4160 struct mgmt_ev_adv_monitor_added ev;
4161
4162 ev.monitor_handle = cpu_to_le16(handle);
4163
4164 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
4165}
4166
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004167static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4168 void *data, u16 len)
4169{
4170 struct adv_monitor *monitor = NULL;
4171 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004172 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004173 size_t rp_size = 0;
4174 __u32 supported = 0;
4175 __u16 num_handles = 0;
4176 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4177
4178 BT_DBG("request for %s", hdev->name);
4179
4180 hci_dev_lock(hdev);
4181
4182 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
4183 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4184
4185 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
4186 handles[num_handles++] = monitor->handle;
4187 }
4188
4189 hci_dev_unlock(hdev);
4190
4191 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4192 rp = kmalloc(rp_size, GFP_KERNEL);
4193 if (!rp)
4194 return -ENOMEM;
4195
4196 /* Once controller-based monitoring is in place, the enabled_features
4197 * should reflect the use.
4198 */
4199 rp->supported_features = cpu_to_le32(supported);
4200 rp->enabled_features = 0;
4201 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4202 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4203 rp->num_handles = cpu_to_le16(num_handles);
4204 if (num_handles)
4205 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4206
Peilin Yecafd4722020-09-09 03:25:51 -04004207 err = mgmt_cmd_complete(sk, hdev->id,
4208 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4209 MGMT_STATUS_SUCCESS, rp, rp_size);
4210
4211 kfree(rp);
4212
4213 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004214}
4215
Miao-chen Choub1395532020-06-17 16:39:14 +02004216static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4217 void *data, u16 len)
4218{
4219 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4220 struct mgmt_rp_add_adv_patterns_monitor rp;
4221 struct adv_monitor *m = NULL;
4222 struct adv_pattern *p = NULL;
Miao-chen Choub52729f2020-06-17 16:39:16 +02004223 unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
Miao-chen Choub1395532020-06-17 16:39:14 +02004224 __u8 cp_ofst = 0, cp_len = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004225 int err, i;
4226
4227 BT_DBG("request for %s", hdev->name);
4228
4229 if (len <= sizeof(*cp) || cp->pattern_count == 0) {
4230 err = mgmt_cmd_status(sk, hdev->id,
4231 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4232 MGMT_STATUS_INVALID_PARAMS);
4233 goto failed;
4234 }
4235
4236 m = kmalloc(sizeof(*m), GFP_KERNEL);
4237 if (!m) {
4238 err = -ENOMEM;
4239 goto failed;
4240 }
4241
4242 INIT_LIST_HEAD(&m->patterns);
4243 m->active = false;
4244
4245 for (i = 0; i < cp->pattern_count; i++) {
4246 if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
4247 err = mgmt_cmd_status(sk, hdev->id,
4248 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4249 MGMT_STATUS_INVALID_PARAMS);
4250 goto failed;
4251 }
4252
4253 cp_ofst = cp->patterns[i].offset;
4254 cp_len = cp->patterns[i].length;
4255 if (cp_ofst >= HCI_MAX_AD_LENGTH ||
4256 cp_len > HCI_MAX_AD_LENGTH ||
4257 (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
4258 err = mgmt_cmd_status(sk, hdev->id,
4259 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4260 MGMT_STATUS_INVALID_PARAMS);
4261 goto failed;
4262 }
4263
4264 p = kmalloc(sizeof(*p), GFP_KERNEL);
4265 if (!p) {
4266 err = -ENOMEM;
4267 goto failed;
4268 }
4269
4270 p->ad_type = cp->patterns[i].ad_type;
4271 p->offset = cp->patterns[i].offset;
4272 p->length = cp->patterns[i].length;
4273 memcpy(p->value, cp->patterns[i].value, p->length);
4274
4275 INIT_LIST_HEAD(&p->list);
4276 list_add(&p->list, &m->patterns);
4277 }
4278
4279 if (mp_cnt != cp->pattern_count) {
4280 err = mgmt_cmd_status(sk, hdev->id,
4281 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4282 MGMT_STATUS_INVALID_PARAMS);
4283 goto failed;
4284 }
4285
4286 hci_dev_lock(hdev);
4287
Miao-chen Choub52729f2020-06-17 16:39:16 +02004288 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4289
Miao-chen Choub1395532020-06-17 16:39:14 +02004290 err = hci_add_adv_monitor(hdev, m);
4291 if (err) {
4292 if (err == -ENOSPC) {
4293 mgmt_cmd_status(sk, hdev->id,
4294 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4295 MGMT_STATUS_NO_RESOURCES);
4296 }
4297 goto unlock;
4298 }
4299
Miao-chen Choub52729f2020-06-17 16:39:16 +02004300 if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt)
4301 mgmt_adv_monitor_added(sk, hdev, m->handle);
4302
Miao-chen Choub1395532020-06-17 16:39:14 +02004303 hci_dev_unlock(hdev);
4304
4305 rp.monitor_handle = cpu_to_le16(m->handle);
4306
4307 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4308 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4309
4310unlock:
4311 hci_dev_unlock(hdev);
4312
4313failed:
4314 hci_free_adv_monitor(m);
4315 return err;
4316}
4317
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004318static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4319 void *data, u16 len)
4320{
4321 struct mgmt_cp_remove_adv_monitor *cp = data;
4322 struct mgmt_rp_remove_adv_monitor rp;
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004323 unsigned int prev_adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004324 u16 handle;
4325 int err;
4326
4327 BT_DBG("request for %s", hdev->name);
4328
4329 hci_dev_lock(hdev);
4330
4331 handle = __le16_to_cpu(cp->monitor_handle);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004332 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004333
4334 err = hci_remove_adv_monitor(hdev, handle);
4335 if (err == -ENOENT) {
4336 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4337 MGMT_STATUS_INVALID_INDEX);
4338 goto unlock;
4339 }
4340
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004341 if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt)
4342 mgmt_adv_monitor_removed(sk, hdev, handle);
4343
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004344 hci_dev_unlock(hdev);
4345
4346 rp.monitor_handle = cp->monitor_handle;
4347
4348 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4349 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4350
4351unlock:
4352 hci_dev_unlock(hdev);
4353 return err;
4354}
4355
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004356static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4357 u16 opcode, struct sk_buff *skb)
4358{
4359 struct mgmt_rp_read_local_oob_data mgmt_rp;
4360 size_t rp_size = sizeof(mgmt_rp);
4361 struct mgmt_pending_cmd *cmd;
4362
Marcel Holtmann181d6952020-05-06 09:57:47 +02004363 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004364
4365 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4366 if (!cmd)
4367 return;
4368
4369 if (status || !skb) {
4370 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4371 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4372 goto remove;
4373 }
4374
4375 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4376
4377 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4378 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4379
4380 if (skb->len < sizeof(*rp)) {
4381 mgmt_cmd_status(cmd->sk, hdev->id,
4382 MGMT_OP_READ_LOCAL_OOB_DATA,
4383 MGMT_STATUS_FAILED);
4384 goto remove;
4385 }
4386
4387 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4388 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4389
4390 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4391 } else {
4392 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4393
4394 if (skb->len < sizeof(*rp)) {
4395 mgmt_cmd_status(cmd->sk, hdev->id,
4396 MGMT_OP_READ_LOCAL_OOB_DATA,
4397 MGMT_STATUS_FAILED);
4398 goto remove;
4399 }
4400
4401 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4402 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4403
4404 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4405 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4406 }
4407
4408 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4409 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4410
4411remove:
4412 mgmt_pending_remove(cmd);
4413}
4414
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004415static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004416 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004417{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004418 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004419 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004420 int err;
4421
Marcel Holtmann181d6952020-05-06 09:57:47 +02004422 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004424 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004425
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004426 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004427 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4428 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004429 goto unlock;
4430 }
4431
Andre Guedes9a1a1992012-07-24 15:03:48 -03004432 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004433 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4434 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004435 goto unlock;
4436 }
4437
Johan Hedberg333ae952015-03-17 13:48:47 +02004438 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004439 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4440 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004441 goto unlock;
4442 }
4443
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004444 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004445 if (!cmd) {
4446 err = -ENOMEM;
4447 goto unlock;
4448 }
4449
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004450 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004451
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004452 if (bredr_sc_enabled(hdev))
4453 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4454 else
4455 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4456
4457 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004458 if (err < 0)
4459 mgmt_pending_remove(cmd);
4460
4461unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004462 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004463 return err;
4464}
4465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004466static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004467 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004468{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004469 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004470 int err;
4471
Marcel Holtmann181d6952020-05-06 09:57:47 +02004472 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004473
Johan Hedberg5d57e792015-01-23 10:10:38 +02004474 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004475 return mgmt_cmd_complete(sk, hdev->id,
4476 MGMT_OP_ADD_REMOTE_OOB_DATA,
4477 MGMT_STATUS_INVALID_PARAMS,
4478 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004480 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004481
Marcel Holtmannec109112014-01-10 02:07:30 -08004482 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4483 struct mgmt_cp_add_remote_oob_data *cp = data;
4484 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004485
Johan Hedbergc19a4952014-11-17 20:52:19 +02004486 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004487 err = mgmt_cmd_complete(sk, hdev->id,
4488 MGMT_OP_ADD_REMOTE_OOB_DATA,
4489 MGMT_STATUS_INVALID_PARAMS,
4490 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004491 goto unlock;
4492 }
4493
Marcel Holtmannec109112014-01-10 02:07:30 -08004494 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004495 cp->addr.type, cp->hash,
4496 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004497 if (err < 0)
4498 status = MGMT_STATUS_FAILED;
4499 else
4500 status = MGMT_STATUS_SUCCESS;
4501
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004502 err = mgmt_cmd_complete(sk, hdev->id,
4503 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4504 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004505 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4506 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004507 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004508 u8 status;
4509
Johan Hedberg86df9202014-10-26 20:52:27 +01004510 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004511 /* Enforce zero-valued 192-bit parameters as
4512 * long as legacy SMP OOB isn't implemented.
4513 */
4514 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4515 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004516 err = mgmt_cmd_complete(sk, hdev->id,
4517 MGMT_OP_ADD_REMOTE_OOB_DATA,
4518 MGMT_STATUS_INVALID_PARAMS,
4519 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004520 goto unlock;
4521 }
4522
Johan Hedberg86df9202014-10-26 20:52:27 +01004523 rand192 = NULL;
4524 hash192 = NULL;
4525 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004526 /* In case one of the P-192 values is set to zero,
4527 * then just disable OOB data for P-192.
4528 */
4529 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4530 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4531 rand192 = NULL;
4532 hash192 = NULL;
4533 } else {
4534 rand192 = cp->rand192;
4535 hash192 = cp->hash192;
4536 }
4537 }
4538
4539 /* In case one of the P-256 values is set to zero, then just
4540 * disable OOB data for P-256.
4541 */
4542 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4543 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4544 rand256 = NULL;
4545 hash256 = NULL;
4546 } else {
4547 rand256 = cp->rand256;
4548 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004549 }
4550
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004551 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004552 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004553 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004554 if (err < 0)
4555 status = MGMT_STATUS_FAILED;
4556 else
4557 status = MGMT_STATUS_SUCCESS;
4558
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004559 err = mgmt_cmd_complete(sk, hdev->id,
4560 MGMT_OP_ADD_REMOTE_OOB_DATA,
4561 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004562 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004563 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4564 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004565 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4566 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004567 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004568
Johan Hedbergc19a4952014-11-17 20:52:19 +02004569unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004570 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004571 return err;
4572}
4573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004574static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004575 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004576{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004577 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004578 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004579 int err;
4580
Marcel Holtmann181d6952020-05-06 09:57:47 +02004581 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004582
Johan Hedbergc19a4952014-11-17 20:52:19 +02004583 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004584 return mgmt_cmd_complete(sk, hdev->id,
4585 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4586 MGMT_STATUS_INVALID_PARAMS,
4587 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004588
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004589 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004590
Johan Hedbergeedbd582014-11-15 09:34:23 +02004591 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4592 hci_remote_oob_data_clear(hdev);
4593 status = MGMT_STATUS_SUCCESS;
4594 goto done;
4595 }
4596
Johan Hedberg6928a922014-10-26 20:46:09 +01004597 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004598 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004599 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004600 else
Szymon Janca6785be2012-12-13 15:11:21 +01004601 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004602
Johan Hedbergeedbd582014-11-15 09:34:23 +02004603done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004604 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4605 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004607 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004608 return err;
4609}
4610
Johan Hedberge68f0722015-11-11 08:30:30 +02004611void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004612{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004613 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004614
Marcel Holtmann181d6952020-05-06 09:57:47 +02004615 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004616
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004617 hci_dev_lock(hdev);
4618
Johan Hedberg333ae952015-03-17 13:48:47 +02004619 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004620 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004621 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004622
Johan Hedberg78b781c2016-01-05 13:19:32 +02004623 if (!cmd)
4624 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4625
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004626 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004627 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004628 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004629 }
4630
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004631 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004632
4633 /* Handle suspend notifier */
4634 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4635 hdev->suspend_tasks)) {
4636 bt_dev_dbg(hdev, "Unpaused discovery");
4637 wake_up(&hdev->suspend_wait_q);
4638 }
Andre Guedes7c307722013-04-30 15:29:28 -03004639}
4640
Johan Hedberg591752a2015-11-11 08:11:24 +02004641static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4642 uint8_t *mgmt_status)
4643{
4644 switch (type) {
4645 case DISCOV_TYPE_LE:
4646 *mgmt_status = mgmt_le_support(hdev);
4647 if (*mgmt_status)
4648 return false;
4649 break;
4650 case DISCOV_TYPE_INTERLEAVED:
4651 *mgmt_status = mgmt_le_support(hdev);
4652 if (*mgmt_status)
4653 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05004654 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02004655 case DISCOV_TYPE_BREDR:
4656 *mgmt_status = mgmt_bredr_support(hdev);
4657 if (*mgmt_status)
4658 return false;
4659 break;
4660 default:
4661 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4662 return false;
4663 }
4664
4665 return true;
4666}
4667
Johan Hedberg78b781c2016-01-05 13:19:32 +02004668static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4669 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004670{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004671 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004672 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004673 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004674 int err;
4675
Marcel Holtmann181d6952020-05-06 09:57:47 +02004676 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004678 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004679
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004680 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004681 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004682 MGMT_STATUS_NOT_POWERED,
4683 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004684 goto failed;
4685 }
4686
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004687 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004688 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004689 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4690 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004691 goto failed;
4692 }
4693
Johan Hedberg591752a2015-11-11 08:11:24 +02004694 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004695 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4696 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004697 goto failed;
4698 }
4699
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004700 /* Can't start discovery when it is paused */
4701 if (hdev->discovery_paused) {
4702 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4703 &cp->type, sizeof(cp->type));
4704 goto failed;
4705 }
4706
Marcel Holtmann22078802014-12-05 11:45:22 +01004707 /* Clear the discovery filter first to free any previously
4708 * allocated memory for the UUID list.
4709 */
4710 hci_discovery_filter_clear(hdev);
4711
Andre Guedes4aab14e2012-02-17 20:39:36 -03004712 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004713 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004714 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4715 hdev->discovery.limited = true;
4716 else
4717 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004718
Johan Hedberg78b781c2016-01-05 13:19:32 +02004719 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004720 if (!cmd) {
4721 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004722 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004723 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004724
Johan Hedberge68f0722015-11-11 08:30:30 +02004725 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004726
4727 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004728 queue_work(hdev->req_workqueue, &hdev->discov_update);
4729 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004730
4731failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004732 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004733 return err;
4734}
4735
Johan Hedberg78b781c2016-01-05 13:19:32 +02004736static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4737 void *data, u16 len)
4738{
4739 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4740 data, len);
4741}
4742
4743static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4744 void *data, u16 len)
4745{
4746 return start_discovery_internal(sk, hdev,
4747 MGMT_OP_START_LIMITED_DISCOVERY,
4748 data, len);
4749}
4750
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004751static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4752 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004753{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004754 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4755 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004756}
4757
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004758static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4759 void *data, u16 len)
4760{
4761 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004762 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004763 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4764 u16 uuid_count, expected_len;
4765 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004766 int err;
4767
Marcel Holtmann181d6952020-05-06 09:57:47 +02004768 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004769
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004770 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004771
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004772 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004773 err = mgmt_cmd_complete(sk, hdev->id,
4774 MGMT_OP_START_SERVICE_DISCOVERY,
4775 MGMT_STATUS_NOT_POWERED,
4776 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004777 goto failed;
4778 }
4779
4780 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004781 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004782 err = mgmt_cmd_complete(sk, hdev->id,
4783 MGMT_OP_START_SERVICE_DISCOVERY,
4784 MGMT_STATUS_BUSY, &cp->type,
4785 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004786 goto failed;
4787 }
4788
4789 uuid_count = __le16_to_cpu(cp->uuid_count);
4790 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004791 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4792 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004793 err = mgmt_cmd_complete(sk, hdev->id,
4794 MGMT_OP_START_SERVICE_DISCOVERY,
4795 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4796 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004797 goto failed;
4798 }
4799
4800 expected_len = sizeof(*cp) + uuid_count * 16;
4801 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004802 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4803 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004804 err = mgmt_cmd_complete(sk, hdev->id,
4805 MGMT_OP_START_SERVICE_DISCOVERY,
4806 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4807 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004808 goto failed;
4809 }
4810
Johan Hedberg591752a2015-11-11 08:11:24 +02004811 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4812 err = mgmt_cmd_complete(sk, hdev->id,
4813 MGMT_OP_START_SERVICE_DISCOVERY,
4814 status, &cp->type, sizeof(cp->type));
4815 goto failed;
4816 }
4817
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004818 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004819 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004820 if (!cmd) {
4821 err = -ENOMEM;
4822 goto failed;
4823 }
4824
Johan Hedberg2922a942014-12-05 13:36:06 +02004825 cmd->cmd_complete = service_discovery_cmd_complete;
4826
Marcel Holtmann22078802014-12-05 11:45:22 +01004827 /* Clear the discovery filter first to free any previously
4828 * allocated memory for the UUID list.
4829 */
4830 hci_discovery_filter_clear(hdev);
4831
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004832 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004833 hdev->discovery.type = cp->type;
4834 hdev->discovery.rssi = cp->rssi;
4835 hdev->discovery.uuid_count = uuid_count;
4836
4837 if (uuid_count > 0) {
4838 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4839 GFP_KERNEL);
4840 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004841 err = mgmt_cmd_complete(sk, hdev->id,
4842 MGMT_OP_START_SERVICE_DISCOVERY,
4843 MGMT_STATUS_FAILED,
4844 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004845 mgmt_pending_remove(cmd);
4846 goto failed;
4847 }
4848 }
4849
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004850 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004851 queue_work(hdev->req_workqueue, &hdev->discov_update);
4852 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004853
4854failed:
4855 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004856 return err;
4857}
4858
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004859void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004860{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004861 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004862
Marcel Holtmann181d6952020-05-06 09:57:47 +02004863 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004864
4865 hci_dev_lock(hdev);
4866
Johan Hedberg333ae952015-03-17 13:48:47 +02004867 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004868 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004869 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004870 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004871 }
4872
Andre Guedes0e05bba2013-04-30 15:29:33 -03004873 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004874
4875 /* Handle suspend notifier */
4876 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4877 bt_dev_dbg(hdev, "Paused discovery");
4878 wake_up(&hdev->suspend_wait_q);
4879 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004880}
4881
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004882static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004883 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004884{
Johan Hedbergd9306502012-02-20 23:25:18 +02004885 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004886 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004887 int err;
4888
Marcel Holtmann181d6952020-05-06 09:57:47 +02004889 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004891 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004892
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004893 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004894 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4895 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4896 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004897 goto unlock;
4898 }
4899
4900 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004901 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4902 MGMT_STATUS_INVALID_PARAMS,
4903 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004904 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004905 }
4906
Johan Hedberg2922a942014-12-05 13:36:06 +02004907 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004908 if (!cmd) {
4909 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004910 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004911 }
4912
Johan Hedberg2922a942014-12-05 13:36:06 +02004913 cmd->cmd_complete = generic_cmd_complete;
4914
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004915 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4916 queue_work(hdev->req_workqueue, &hdev->discov_update);
4917 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004918
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004919unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004920 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004921 return err;
4922}
4923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004924static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004925 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004926{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004927 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004928 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004929 int err;
4930
Marcel Holtmann181d6952020-05-06 09:57:47 +02004931 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004932
Johan Hedberg561aafb2012-01-04 13:31:59 +02004933 hci_dev_lock(hdev);
4934
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004935 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004936 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4937 MGMT_STATUS_FAILED, &cp->addr,
4938 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004939 goto failed;
4940 }
4941
Johan Hedberga198e7b2012-02-17 14:27:06 +02004942 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004943 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004944 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4945 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4946 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004947 goto failed;
4948 }
4949
4950 if (cp->name_known) {
4951 e->name_state = NAME_KNOWN;
4952 list_del(&e->list);
4953 } else {
4954 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004955 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004956 }
4957
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004958 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4959 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004960
4961failed:
4962 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004963 return err;
4964}
4965
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004966static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004967 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004968{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004969 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004970 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004971 int err;
4972
Marcel Holtmann181d6952020-05-06 09:57:47 +02004973 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004974
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004975 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004976 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4977 MGMT_STATUS_INVALID_PARAMS,
4978 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004979
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004980 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004981
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004982 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4983 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004984 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004985 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004986 goto done;
4987 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004988
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004989 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4990 sk);
4991 status = MGMT_STATUS_SUCCESS;
4992
4993done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004994 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4995 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004997 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004998
4999 return err;
5000}
5001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005002static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005003 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005005 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005006 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005007 int err;
5008
Marcel Holtmann181d6952020-05-06 09:57:47 +02005009 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005010
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005011 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005012 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5013 MGMT_STATUS_INVALID_PARAMS,
5014 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005016 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005017
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005018 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
5019 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005020 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005021 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005022 goto done;
5023 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005024
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005025 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5026 sk);
5027 status = MGMT_STATUS_SUCCESS;
5028
5029done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005030 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5031 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005033 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005034
5035 return err;
5036}
5037
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005038static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5039 u16 len)
5040{
5041 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05005042 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005043 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005044 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005045
Marcel Holtmann181d6952020-05-06 09:57:47 +02005046 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005047
Szymon Jancc72d4b82012-03-16 16:02:57 +01005048 source = __le16_to_cpu(cp->source);
5049
5050 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005051 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5052 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005053
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005054 hci_dev_lock(hdev);
5055
Szymon Jancc72d4b82012-03-16 16:02:57 +01005056 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005057 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5058 hdev->devid_product = __le16_to_cpu(cp->product);
5059 hdev->devid_version = __le16_to_cpu(cp->version);
5060
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005061 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5062 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005063
Johan Hedberg890ea892013-03-15 17:06:52 -05005064 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02005065 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05005066 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005067
5068 hci_dev_unlock(hdev);
5069
5070 return err;
5071}
5072
Arman Uguray24b4f382015-03-23 15:57:12 -07005073static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5074 u16 opcode)
5075{
Marcel Holtmann181d6952020-05-06 09:57:47 +02005076 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005077}
5078
Marcel Holtmann1904a852015-01-11 13:50:44 -08005079static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5080 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005081{
5082 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005083 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005084 u8 instance;
5085 struct adv_info *adv_instance;
5086 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005087
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305088 hci_dev_lock(hdev);
5089
Johan Hedberg4375f102013-09-25 13:26:10 +03005090 if (status) {
5091 u8 mgmt_err = mgmt_status(status);
5092
5093 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5094 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305095 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005096 }
5097
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005098 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005099 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005100 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005101 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005102
Johan Hedberg4375f102013-09-25 13:26:10 +03005103 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5104 &match);
5105
5106 new_settings(hdev, match.sk);
5107
5108 if (match.sk)
5109 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305110
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005111 /* Handle suspend notifier */
5112 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5113 hdev->suspend_tasks)) {
5114 bt_dev_dbg(hdev, "Paused advertising");
5115 wake_up(&hdev->suspend_wait_q);
5116 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5117 hdev->suspend_tasks)) {
5118 bt_dev_dbg(hdev, "Unpaused advertising");
5119 wake_up(&hdev->suspend_wait_q);
5120 }
5121
Arman Uguray24b4f382015-03-23 15:57:12 -07005122 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005123 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005124 */
5125 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005126 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005127 goto unlock;
5128
Florian Grandel7816b822015-06-18 03:16:45 +02005129 instance = hdev->cur_adv_instance;
5130 if (!instance) {
5131 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5132 struct adv_info, list);
5133 if (!adv_instance)
5134 goto unlock;
5135
5136 instance = adv_instance->instance;
5137 }
5138
Arman Uguray24b4f382015-03-23 15:57:12 -07005139 hci_req_init(&req, hdev);
5140
Johan Hedbergf2252572015-11-18 12:49:20 +02005141 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005142
Florian Grandel7816b822015-06-18 03:16:45 +02005143 if (!err)
5144 err = hci_req_run(&req, enable_advertising_instance);
5145
5146 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005147 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005148
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305149unlock:
5150 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005151}
5152
Marcel Holtmann21b51872013-10-10 09:47:53 -07005153static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5154 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005155{
5156 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005157 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005158 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005159 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005160 int err;
5161
Marcel Holtmann181d6952020-05-06 09:57:47 +02005162 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005163
Johan Hedberge6fe7982013-10-02 15:45:22 +03005164 status = mgmt_le_support(hdev);
5165 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005166 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5167 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005168
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05305169 /* Enabling the experimental LL Privay support disables support for
5170 * advertising.
5171 */
5172 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
5173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5174 MGMT_STATUS_NOT_SUPPORTED);
5175
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005176 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005177 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5178 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005179
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005180 if (hdev->advertising_paused)
5181 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5182 MGMT_STATUS_BUSY);
5183
Johan Hedberg4375f102013-09-25 13:26:10 +03005184 hci_dev_lock(hdev);
5185
5186 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005187
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005188 /* The following conditions are ones which mean that we should
5189 * not do any HCI communication but directly send a mgmt
5190 * response to user space (after toggling the flag if
5191 * necessary).
5192 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005193 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005194 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5195 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005196 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005197 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005198 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005199 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005200
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005201 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005202 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005203 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005204 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005205 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005206 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005207 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005208 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005209 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005210 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005211 }
5212
5213 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5214 if (err < 0)
5215 goto unlock;
5216
5217 if (changed)
5218 err = new_settings(hdev, sk);
5219
5220 goto unlock;
5221 }
5222
Johan Hedberg333ae952015-03-17 13:48:47 +02005223 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5224 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005225 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5226 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005227 goto unlock;
5228 }
5229
5230 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5231 if (!cmd) {
5232 err = -ENOMEM;
5233 goto unlock;
5234 }
5235
5236 hci_req_init(&req, hdev);
5237
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005238 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005239 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005240 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005241 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005242
Florian Grandel7816b822015-06-18 03:16:45 +02005243 cancel_adv_timeout(hdev);
5244
Arman Uguray24b4f382015-03-23 15:57:12 -07005245 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005246 /* Switch to instance "0" for the Set Advertising setting.
5247 * We cannot use update_[adv|scan_rsp]_data() here as the
5248 * HCI_ADVERTISING flag is not yet set.
5249 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005250 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305251
5252 if (ext_adv_capable(hdev)) {
5253 __hci_req_start_ext_adv(&req, 0x00);
5254 } else {
5255 __hci_req_update_adv_data(&req, 0x00);
5256 __hci_req_update_scan_rsp_data(&req, 0x00);
5257 __hci_req_enable_advertising(&req);
5258 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005259 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005260 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005261 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005262
5263 err = hci_req_run(&req, set_advertising_complete);
5264 if (err < 0)
5265 mgmt_pending_remove(cmd);
5266
5267unlock:
5268 hci_dev_unlock(hdev);
5269 return err;
5270}
5271
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005272static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5273 void *data, u16 len)
5274{
5275 struct mgmt_cp_set_static_address *cp = data;
5276 int err;
5277
Marcel Holtmann181d6952020-05-06 09:57:47 +02005278 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005279
Marcel Holtmann62af4442013-10-02 22:10:32 -07005280 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005281 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5282 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005283
5284 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005285 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5286 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005287
5288 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5289 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005290 return mgmt_cmd_status(sk, hdev->id,
5291 MGMT_OP_SET_STATIC_ADDRESS,
5292 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005293
5294 /* Two most significant bits shall be set */
5295 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005296 return mgmt_cmd_status(sk, hdev->id,
5297 MGMT_OP_SET_STATIC_ADDRESS,
5298 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005299 }
5300
5301 hci_dev_lock(hdev);
5302
5303 bacpy(&hdev->static_addr, &cp->bdaddr);
5304
Marcel Holtmann93690c22015-03-06 10:11:21 -08005305 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5306 if (err < 0)
5307 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005308
Marcel Holtmann93690c22015-03-06 10:11:21 -08005309 err = new_settings(hdev, sk);
5310
5311unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005312 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005313 return err;
5314}
5315
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005316static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5317 void *data, u16 len)
5318{
5319 struct mgmt_cp_set_scan_params *cp = data;
5320 __u16 interval, window;
5321 int err;
5322
Marcel Holtmann181d6952020-05-06 09:57:47 +02005323 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005324
5325 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005326 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5327 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005328
5329 interval = __le16_to_cpu(cp->interval);
5330
5331 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005332 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5333 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005334
5335 window = __le16_to_cpu(cp->window);
5336
5337 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005338 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5339 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005340
Marcel Holtmann899e1072013-10-14 09:55:32 -07005341 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005342 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5343 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005344
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005345 hci_dev_lock(hdev);
5346
5347 hdev->le_scan_interval = interval;
5348 hdev->le_scan_window = window;
5349
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5351 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005352
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005353 /* If background scan is running, restart it so new parameters are
5354 * loaded.
5355 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005356 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005357 hdev->discovery.state == DISCOVERY_STOPPED) {
5358 struct hci_request req;
5359
5360 hci_req_init(&req, hdev);
5361
Sathish Narasimman5c49bcc2020-07-23 18:09:01 +05305362 hci_req_add_le_scan_disable(&req, false);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005363 hci_req_add_le_passive_scan(&req);
5364
5365 hci_req_run(&req, NULL);
5366 }
5367
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005368 hci_dev_unlock(hdev);
5369
5370 return err;
5371}
5372
Marcel Holtmann1904a852015-01-11 13:50:44 -08005373static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5374 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005375{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005376 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005377
Marcel Holtmann181d6952020-05-06 09:57:47 +02005378 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005379
5380 hci_dev_lock(hdev);
5381
Johan Hedberg333ae952015-03-17 13:48:47 +02005382 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005383 if (!cmd)
5384 goto unlock;
5385
5386 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005387 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5388 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005389 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005390 struct mgmt_mode *cp = cmd->param;
5391
5392 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005393 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005394 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005395 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005396
Johan Hedberg33e38b32013-03-15 17:07:05 -05005397 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5398 new_settings(hdev, cmd->sk);
5399 }
5400
5401 mgmt_pending_remove(cmd);
5402
5403unlock:
5404 hci_dev_unlock(hdev);
5405}
5406
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005407static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005408 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005409{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005410 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005411 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005412 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005413 int err;
5414
Marcel Holtmann181d6952020-05-06 09:57:47 +02005415 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005416
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005417 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005418 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005419 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5420 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005421
Johan Hedberga7e80f22013-01-09 16:05:19 +02005422 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005425
Antti Julkuf6422ec2011-06-22 13:11:56 +03005426 hci_dev_lock(hdev);
5427
Johan Hedberg333ae952015-03-17 13:48:47 +02005428 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005429 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5430 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005431 goto unlock;
5432 }
5433
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005434 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005435 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5436 hdev);
5437 goto unlock;
5438 }
5439
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005440 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005441 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005442 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5443 hdev);
5444 new_settings(hdev, sk);
5445 goto unlock;
5446 }
5447
Johan Hedberg33e38b32013-03-15 17:07:05 -05005448 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5449 data, len);
5450 if (!cmd) {
5451 err = -ENOMEM;
5452 goto unlock;
5453 }
5454
5455 hci_req_init(&req, hdev);
5456
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005457 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005458
5459 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005460 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005461 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5462 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005463 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005464 }
5465
Johan Hedberg33e38b32013-03-15 17:07:05 -05005466unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005467 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005468
Antti Julkuf6422ec2011-06-22 13:11:56 +03005469 return err;
5470}
5471
Marcel Holtmann1904a852015-01-11 13:50:44 -08005472static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005473{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005474 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005475
Marcel Holtmann181d6952020-05-06 09:57:47 +02005476 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005477
5478 hci_dev_lock(hdev);
5479
Johan Hedberg333ae952015-03-17 13:48:47 +02005480 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005481 if (!cmd)
5482 goto unlock;
5483
5484 if (status) {
5485 u8 mgmt_err = mgmt_status(status);
5486
5487 /* We need to restore the flag if related HCI commands
5488 * failed.
5489 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005490 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005491
Johan Hedberga69e8372015-03-06 21:08:53 +02005492 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005493 } else {
5494 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5495 new_settings(hdev, cmd->sk);
5496 }
5497
5498 mgmt_pending_remove(cmd);
5499
5500unlock:
5501 hci_dev_unlock(hdev);
5502}
5503
5504static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5505{
5506 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005507 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005508 struct hci_request req;
5509 int err;
5510
Marcel Holtmann181d6952020-05-06 09:57:47 +02005511 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005512
5513 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005514 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5515 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005516
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005517 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005518 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5519 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005520
5521 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005522 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5523 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005524
5525 hci_dev_lock(hdev);
5526
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005527 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005528 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5529 goto unlock;
5530 }
5531
5532 if (!hdev_is_powered(hdev)) {
5533 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005534 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5535 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5536 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5537 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5538 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005539 }
5540
Marcel Holtmannce05d602015-03-13 02:11:03 -07005541 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005542
5543 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5544 if (err < 0)
5545 goto unlock;
5546
5547 err = new_settings(hdev, sk);
5548 goto unlock;
5549 }
5550
5551 /* Reject disabling when powered on */
5552 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005553 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5554 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005555 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005556 } else {
5557 /* When configuring a dual-mode controller to operate
5558 * with LE only and using a static address, then switching
5559 * BR/EDR back on is not allowed.
5560 *
5561 * Dual-mode controllers shall operate with the public
5562 * address as its identity address for BR/EDR and LE. So
5563 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005564 *
5565 * The same restrictions applies when secure connections
5566 * has been enabled. For BR/EDR this is a controller feature
5567 * while for LE it is a host stack feature. This means that
5568 * switching BR/EDR back on when secure connections has been
5569 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005570 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005571 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005572 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005573 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005574 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5575 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005576 goto unlock;
5577 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005578 }
5579
Johan Hedberg333ae952015-03-17 13:48:47 +02005580 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005581 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5582 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005583 goto unlock;
5584 }
5585
5586 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5587 if (!cmd) {
5588 err = -ENOMEM;
5589 goto unlock;
5590 }
5591
Johan Hedbergf2252572015-11-18 12:49:20 +02005592 /* We need to flip the bit already here so that
5593 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005594 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005595 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005596
5597 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005598
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005599 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005600 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005601
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005602 /* Since only the advertising data flags will change, there
5603 * is no need to update the scan response data.
5604 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005605 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005606
Johan Hedberg0663ca22013-10-02 13:43:14 +03005607 err = hci_req_run(&req, set_bredr_complete);
5608 if (err < 0)
5609 mgmt_pending_remove(cmd);
5610
5611unlock:
5612 hci_dev_unlock(hdev);
5613 return err;
5614}
5615
Johan Hedberga1443f52015-01-23 15:42:46 +02005616static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5617{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005618 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005619 struct mgmt_mode *cp;
5620
Marcel Holtmann181d6952020-05-06 09:57:47 +02005621 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005622
5623 hci_dev_lock(hdev);
5624
Johan Hedberg333ae952015-03-17 13:48:47 +02005625 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005626 if (!cmd)
5627 goto unlock;
5628
5629 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005630 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5631 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005632 goto remove;
5633 }
5634
5635 cp = cmd->param;
5636
5637 switch (cp->val) {
5638 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005639 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5640 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005641 break;
5642 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005643 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005644 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005645 break;
5646 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005647 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5648 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005649 break;
5650 }
5651
5652 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5653 new_settings(hdev, cmd->sk);
5654
5655remove:
5656 mgmt_pending_remove(cmd);
5657unlock:
5658 hci_dev_unlock(hdev);
5659}
5660
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005661static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5662 void *data, u16 len)
5663{
5664 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005665 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005666 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005667 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005668 int err;
5669
Marcel Holtmann181d6952020-05-06 09:57:47 +02005670 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005671
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005672 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005673 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5675 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005676
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005677 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005678 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005679 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005680 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5681 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005682
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005683 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005684 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005685 MGMT_STATUS_INVALID_PARAMS);
5686
5687 hci_dev_lock(hdev);
5688
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005689 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005690 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005691 bool changed;
5692
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005693 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005694 changed = !hci_dev_test_and_set_flag(hdev,
5695 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005696 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005697 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005698 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005699 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005700 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005701 changed = hci_dev_test_and_clear_flag(hdev,
5702 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005703 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005704 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005705
5706 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5707 if (err < 0)
5708 goto failed;
5709
5710 if (changed)
5711 err = new_settings(hdev, sk);
5712
5713 goto failed;
5714 }
5715
Johan Hedberg333ae952015-03-17 13:48:47 +02005716 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005717 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5718 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005719 goto failed;
5720 }
5721
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005722 val = !!cp->val;
5723
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005724 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5725 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005726 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5727 goto failed;
5728 }
5729
5730 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5731 if (!cmd) {
5732 err = -ENOMEM;
5733 goto failed;
5734 }
5735
Johan Hedberga1443f52015-01-23 15:42:46 +02005736 hci_req_init(&req, hdev);
5737 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5738 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005739 if (err < 0) {
5740 mgmt_pending_remove(cmd);
5741 goto failed;
5742 }
5743
5744failed:
5745 hci_dev_unlock(hdev);
5746 return err;
5747}
5748
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005749static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5750 void *data, u16 len)
5751{
5752 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005753 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005754 int err;
5755
Marcel Holtmann181d6952020-05-06 09:57:47 +02005756 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005757
Johan Hedbergb97109792014-06-24 14:00:28 +03005758 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005759 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5760 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005761
5762 hci_dev_lock(hdev);
5763
5764 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005765 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005766 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005767 changed = hci_dev_test_and_clear_flag(hdev,
5768 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005769
Johan Hedbergb97109792014-06-24 14:00:28 +03005770 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005771 use_changed = !hci_dev_test_and_set_flag(hdev,
5772 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005773 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005774 use_changed = hci_dev_test_and_clear_flag(hdev,
5775 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005776
5777 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005778 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005779 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5780 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5781 sizeof(mode), &mode);
5782 }
5783
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005784 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5785 if (err < 0)
5786 goto unlock;
5787
5788 if (changed)
5789 err = new_settings(hdev, sk);
5790
5791unlock:
5792 hci_dev_unlock(hdev);
5793 return err;
5794}
5795
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005796static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5797 u16 len)
5798{
5799 struct mgmt_cp_set_privacy *cp = cp_data;
5800 bool changed;
5801 int err;
5802
Marcel Holtmann181d6952020-05-06 09:57:47 +02005803 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005804
5805 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005806 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5807 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005808
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005809 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005810 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005812
5813 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005814 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5815 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005816
5817 hci_dev_lock(hdev);
5818
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005819 /* If user space supports this command it is also expected to
5820 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5821 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005822 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005823
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005824 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005825 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005826 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005827 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305828 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005829 if (cp->privacy == 0x02)
5830 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5831 else
5832 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005833 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005834 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005835 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005836 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305837 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005838 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005839 }
5840
5841 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5842 if (err < 0)
5843 goto unlock;
5844
5845 if (changed)
5846 err = new_settings(hdev, sk);
5847
5848unlock:
5849 hci_dev_unlock(hdev);
5850 return err;
5851}
5852
Johan Hedberg41edf162014-02-18 10:19:35 +02005853static bool irk_is_valid(struct mgmt_irk_info *irk)
5854{
5855 switch (irk->addr.type) {
5856 case BDADDR_LE_PUBLIC:
5857 return true;
5858
5859 case BDADDR_LE_RANDOM:
5860 /* Two most significant bits shall be set */
5861 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5862 return false;
5863 return true;
5864 }
5865
5866 return false;
5867}
5868
5869static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5870 u16 len)
5871{
5872 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005873 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5874 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005875 u16 irk_count, expected_len;
5876 int i, err;
5877
Marcel Holtmann181d6952020-05-06 09:57:47 +02005878 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005879
5880 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005881 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5882 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005883
5884 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005885 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005886 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5887 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005888 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005890 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005891
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005892 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005893 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005894 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5895 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005896 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5897 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005898 }
5899
Marcel Holtmann181d6952020-05-06 09:57:47 +02005900 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005901
5902 for (i = 0; i < irk_count; i++) {
5903 struct mgmt_irk_info *key = &cp->irks[i];
5904
5905 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005906 return mgmt_cmd_status(sk, hdev->id,
5907 MGMT_OP_LOAD_IRKS,
5908 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005909 }
5910
5911 hci_dev_lock(hdev);
5912
5913 hci_smp_irks_clear(hdev);
5914
5915 for (i = 0; i < irk_count; i++) {
5916 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005917
Alain Michaud600a8742020-01-07 00:43:17 +00005918 if (hci_is_blocked_key(hdev,
5919 HCI_BLOCKED_KEY_TYPE_IRK,
5920 irk->val)) {
5921 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5922 &irk->addr.bdaddr);
5923 continue;
5924 }
5925
Johan Hedberg85813a72015-10-21 18:02:59 +03005926 hci_add_irk(hdev, &irk->addr.bdaddr,
5927 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005928 BDADDR_ANY);
5929 }
5930
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005931 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005932
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005933 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005934
5935 hci_dev_unlock(hdev);
5936
5937 return err;
5938}
5939
Johan Hedberg3f706b72013-01-20 14:27:16 +02005940static bool ltk_is_valid(struct mgmt_ltk_info *key)
5941{
5942 if (key->master != 0x00 && key->master != 0x01)
5943 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005944
5945 switch (key->addr.type) {
5946 case BDADDR_LE_PUBLIC:
5947 return true;
5948
5949 case BDADDR_LE_RANDOM:
5950 /* Two most significant bits shall be set */
5951 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5952 return false;
5953 return true;
5954 }
5955
5956 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005957}
5958
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005959static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005960 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005961{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005962 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005963 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5964 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005965 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005966 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005967
Marcel Holtmann181d6952020-05-06 09:57:47 +02005968 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005969
5970 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005971 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5972 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005973
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005974 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005975 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005976 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5977 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005978 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5979 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005980 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005981
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005982 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005983 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005984 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5985 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005986 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5987 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005988 }
5989
Marcel Holtmann181d6952020-05-06 09:57:47 +02005990 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005991
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005992 for (i = 0; i < key_count; i++) {
5993 struct mgmt_ltk_info *key = &cp->keys[i];
5994
Johan Hedberg3f706b72013-01-20 14:27:16 +02005995 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005996 return mgmt_cmd_status(sk, hdev->id,
5997 MGMT_OP_LOAD_LONG_TERM_KEYS,
5998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005999 }
6000
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006001 hci_dev_lock(hdev);
6002
6003 hci_smp_ltks_clear(hdev);
6004
6005 for (i = 0; i < key_count; i++) {
6006 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006007 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006008
Alain Michaud600a8742020-01-07 00:43:17 +00006009 if (hci_is_blocked_key(hdev,
6010 HCI_BLOCKED_KEY_TYPE_LTK,
6011 key->val)) {
6012 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6013 &key->addr.bdaddr);
6014 continue;
6015 }
6016
Johan Hedberg61b43352014-05-29 19:36:53 +03006017 switch (key->type) {
6018 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006019 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006020 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006021 break;
6022 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006023 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006024 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006025 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006026 case MGMT_LTK_P256_UNAUTH:
6027 authenticated = 0x00;
6028 type = SMP_LTK_P256;
6029 break;
6030 case MGMT_LTK_P256_AUTH:
6031 authenticated = 0x01;
6032 type = SMP_LTK_P256;
6033 break;
6034 case MGMT_LTK_P256_DEBUG:
6035 authenticated = 0x00;
6036 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006037 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006038 default:
6039 continue;
6040 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006041
Johan Hedberg85813a72015-10-21 18:02:59 +03006042 hci_add_ltk(hdev, &key->addr.bdaddr,
6043 le_addr_type(key->addr.type), type, authenticated,
6044 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006045 }
6046
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006047 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006048 NULL, 0);
6049
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006050 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006051
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006052 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006053}
6054
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006055static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006056{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006057 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006058 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006059 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006060
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006061 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006062
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006063 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006064 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006065 rp.tx_power = conn->tx_power;
6066 rp.max_tx_power = conn->max_tx_power;
6067 } else {
6068 rp.rssi = HCI_RSSI_INVALID;
6069 rp.tx_power = HCI_TX_POWER_INVALID;
6070 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006071 }
6072
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006073 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6074 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006075
6076 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006077 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006078
6079 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006080}
6081
Marcel Holtmann1904a852015-01-11 13:50:44 -08006082static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6083 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006084{
6085 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006086 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006087 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006088 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006089 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006090
Marcel Holtmann181d6952020-05-06 09:57:47 +02006091 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006092
6093 hci_dev_lock(hdev);
6094
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006095 /* Commands sent in request are either Read RSSI or Read Transmit Power
6096 * Level so we check which one was last sent to retrieve connection
6097 * handle. Both commands have handle as first parameter so it's safe to
6098 * cast data on the same command struct.
6099 *
6100 * First command sent is always Read RSSI and we fail only if it fails.
6101 * In other case we simply override error to indicate success as we
6102 * already remembered if TX power value is actually valid.
6103 */
6104 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6105 if (!cp) {
6106 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006107 status = MGMT_STATUS_SUCCESS;
6108 } else {
6109 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006110 }
6111
6112 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006113 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006114 goto unlock;
6115 }
6116
6117 handle = __le16_to_cpu(cp->handle);
6118 conn = hci_conn_hash_lookup_handle(hdev, handle);
6119 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006120 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
6121 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006122 goto unlock;
6123 }
6124
Johan Hedberg333ae952015-03-17 13:48:47 +02006125 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006126 if (!cmd)
6127 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006128
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006129 cmd->cmd_complete(cmd, status);
6130 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006131
6132unlock:
6133 hci_dev_unlock(hdev);
6134}
6135
6136static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6137 u16 len)
6138{
6139 struct mgmt_cp_get_conn_info *cp = data;
6140 struct mgmt_rp_get_conn_info rp;
6141 struct hci_conn *conn;
6142 unsigned long conn_info_age;
6143 int err = 0;
6144
Marcel Holtmann181d6952020-05-06 09:57:47 +02006145 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006146
6147 memset(&rp, 0, sizeof(rp));
6148 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6149 rp.addr.type = cp->addr.type;
6150
6151 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006152 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6153 MGMT_STATUS_INVALID_PARAMS,
6154 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006155
6156 hci_dev_lock(hdev);
6157
6158 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006159 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6160 MGMT_STATUS_NOT_POWERED, &rp,
6161 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006162 goto unlock;
6163 }
6164
6165 if (cp->addr.type == BDADDR_BREDR)
6166 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6167 &cp->addr.bdaddr);
6168 else
6169 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6170
6171 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006172 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6173 MGMT_STATUS_NOT_CONNECTED, &rp,
6174 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006175 goto unlock;
6176 }
6177
Johan Hedberg333ae952015-03-17 13:48:47 +02006178 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006179 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6180 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006181 goto unlock;
6182 }
6183
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006184 /* To avoid client trying to guess when to poll again for information we
6185 * calculate conn info age as random value between min/max set in hdev.
6186 */
6187 conn_info_age = hdev->conn_info_min_age +
6188 prandom_u32_max(hdev->conn_info_max_age -
6189 hdev->conn_info_min_age);
6190
6191 /* Query controller to refresh cached values if they are too old or were
6192 * never read.
6193 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006194 if (time_after(jiffies, conn->conn_info_timestamp +
6195 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006196 !conn->conn_info_timestamp) {
6197 struct hci_request req;
6198 struct hci_cp_read_tx_power req_txp_cp;
6199 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006200 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006201
6202 hci_req_init(&req, hdev);
6203 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6204 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6205 &req_rssi_cp);
6206
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006207 /* For LE links TX power does not change thus we don't need to
6208 * query for it once value is known.
6209 */
6210 if (!bdaddr_type_is_le(cp->addr.type) ||
6211 conn->tx_power == HCI_TX_POWER_INVALID) {
6212 req_txp_cp.handle = cpu_to_le16(conn->handle);
6213 req_txp_cp.type = 0x00;
6214 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6215 sizeof(req_txp_cp), &req_txp_cp);
6216 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006217
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006218 /* Max TX power needs to be read only once per connection */
6219 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6220 req_txp_cp.handle = cpu_to_le16(conn->handle);
6221 req_txp_cp.type = 0x01;
6222 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6223 sizeof(req_txp_cp), &req_txp_cp);
6224 }
6225
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006226 err = hci_req_run(&req, conn_info_refresh_complete);
6227 if (err < 0)
6228 goto unlock;
6229
6230 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6231 data, len);
6232 if (!cmd) {
6233 err = -ENOMEM;
6234 goto unlock;
6235 }
6236
6237 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006238 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006239 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006240
6241 conn->conn_info_timestamp = jiffies;
6242 } else {
6243 /* Cache is valid, just reply with values cached in hci_conn */
6244 rp.rssi = conn->rssi;
6245 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006246 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006247
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006248 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6249 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006250 }
6251
6252unlock:
6253 hci_dev_unlock(hdev);
6254 return err;
6255}
6256
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006257static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006258{
6259 struct hci_conn *conn = cmd->user_data;
6260 struct mgmt_rp_get_clock_info rp;
6261 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006262 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006263
6264 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006265 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006266
6267 if (status)
6268 goto complete;
6269
6270 hdev = hci_dev_get(cmd->index);
6271 if (hdev) {
6272 rp.local_clock = cpu_to_le32(hdev->clock);
6273 hci_dev_put(hdev);
6274 }
6275
6276 if (conn) {
6277 rp.piconet_clock = cpu_to_le32(conn->clock);
6278 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6279 }
6280
6281complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006282 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6283 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006284
6285 if (conn) {
6286 hci_conn_drop(conn);
6287 hci_conn_put(conn);
6288 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006289
6290 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006291}
6292
Marcel Holtmann1904a852015-01-11 13:50:44 -08006293static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006294{
Johan Hedberg95868422014-06-28 17:54:07 +03006295 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006296 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006297 struct hci_conn *conn;
6298
Marcel Holtmann181d6952020-05-06 09:57:47 +02006299 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006300
6301 hci_dev_lock(hdev);
6302
6303 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6304 if (!hci_cp)
6305 goto unlock;
6306
6307 if (hci_cp->which) {
6308 u16 handle = __le16_to_cpu(hci_cp->handle);
6309 conn = hci_conn_hash_lookup_handle(hdev, handle);
6310 } else {
6311 conn = NULL;
6312 }
6313
Johan Hedberg333ae952015-03-17 13:48:47 +02006314 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006315 if (!cmd)
6316 goto unlock;
6317
Johan Hedberg69487372014-12-05 13:36:07 +02006318 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006319 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006320
6321unlock:
6322 hci_dev_unlock(hdev);
6323}
6324
6325static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6326 u16 len)
6327{
6328 struct mgmt_cp_get_clock_info *cp = data;
6329 struct mgmt_rp_get_clock_info rp;
6330 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006331 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006332 struct hci_request req;
6333 struct hci_conn *conn;
6334 int err;
6335
Marcel Holtmann181d6952020-05-06 09:57:47 +02006336 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006337
6338 memset(&rp, 0, sizeof(rp));
6339 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6340 rp.addr.type = cp->addr.type;
6341
6342 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006343 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6344 MGMT_STATUS_INVALID_PARAMS,
6345 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006346
6347 hci_dev_lock(hdev);
6348
6349 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6351 MGMT_STATUS_NOT_POWERED, &rp,
6352 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006353 goto unlock;
6354 }
6355
6356 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6357 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6358 &cp->addr.bdaddr);
6359 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006360 err = mgmt_cmd_complete(sk, hdev->id,
6361 MGMT_OP_GET_CLOCK_INFO,
6362 MGMT_STATUS_NOT_CONNECTED,
6363 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006364 goto unlock;
6365 }
6366 } else {
6367 conn = NULL;
6368 }
6369
6370 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6371 if (!cmd) {
6372 err = -ENOMEM;
6373 goto unlock;
6374 }
6375
Johan Hedberg69487372014-12-05 13:36:07 +02006376 cmd->cmd_complete = clock_info_cmd_complete;
6377
Johan Hedberg95868422014-06-28 17:54:07 +03006378 hci_req_init(&req, hdev);
6379
6380 memset(&hci_cp, 0, sizeof(hci_cp));
6381 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6382
6383 if (conn) {
6384 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006385 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006386
6387 hci_cp.handle = cpu_to_le16(conn->handle);
6388 hci_cp.which = 0x01; /* Piconet clock */
6389 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6390 }
6391
6392 err = hci_req_run(&req, get_clock_info_complete);
6393 if (err < 0)
6394 mgmt_pending_remove(cmd);
6395
6396unlock:
6397 hci_dev_unlock(hdev);
6398 return err;
6399}
6400
Johan Hedberg5a154e62014-12-19 22:26:02 +02006401static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6402{
6403 struct hci_conn *conn;
6404
6405 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6406 if (!conn)
6407 return false;
6408
6409 if (conn->dst_type != type)
6410 return false;
6411
6412 if (conn->state != BT_CONNECTED)
6413 return false;
6414
6415 return true;
6416}
6417
6418/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006419static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006420 u8 addr_type, u8 auto_connect)
6421{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006422 struct hci_conn_params *params;
6423
6424 params = hci_conn_params_add(hdev, addr, addr_type);
6425 if (!params)
6426 return -EIO;
6427
6428 if (params->auto_connect == auto_connect)
6429 return 0;
6430
6431 list_del_init(&params->action);
6432
6433 switch (auto_connect) {
6434 case HCI_AUTO_CONN_DISABLED:
6435 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006436 /* If auto connect is being disabled when we're trying to
6437 * connect to device, keep connecting.
6438 */
6439 if (params->explicit_connect)
6440 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006441 break;
6442 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006443 if (params->explicit_connect)
6444 list_add(&params->action, &hdev->pend_le_conns);
6445 else
6446 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006447 break;
6448 case HCI_AUTO_CONN_DIRECT:
6449 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006450 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006451 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006452 break;
6453 }
6454
6455 params->auto_connect = auto_connect;
6456
Marcel Holtmann181d6952020-05-06 09:57:47 +02006457 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6458 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006459
6460 return 0;
6461}
6462
Marcel Holtmann8afef092014-06-29 22:28:34 +02006463static void device_added(struct sock *sk, struct hci_dev *hdev,
6464 bdaddr_t *bdaddr, u8 type, u8 action)
6465{
6466 struct mgmt_ev_device_added ev;
6467
6468 bacpy(&ev.addr.bdaddr, bdaddr);
6469 ev.addr.type = type;
6470 ev.action = action;
6471
6472 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6473}
6474
Marcel Holtmann2faade52014-06-29 19:44:03 +02006475static int add_device(struct sock *sk, struct hci_dev *hdev,
6476 void *data, u16 len)
6477{
6478 struct mgmt_cp_add_device *cp = data;
6479 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006480 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006481 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006482 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006483
Marcel Holtmann181d6952020-05-06 09:57:47 +02006484 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006485
Johan Hedberg66593582014-07-09 12:59:14 +03006486 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006487 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006488 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6489 MGMT_STATUS_INVALID_PARAMS,
6490 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006491
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006492 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006493 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6494 MGMT_STATUS_INVALID_PARAMS,
6495 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006496
6497 hci_dev_lock(hdev);
6498
Johan Hedberg66593582014-07-09 12:59:14 +03006499 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006500 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006501 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006502 err = mgmt_cmd_complete(sk, hdev->id,
6503 MGMT_OP_ADD_DEVICE,
6504 MGMT_STATUS_INVALID_PARAMS,
6505 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006506 goto unlock;
6507 }
6508
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006509 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6510 &cp->addr.bdaddr,
6511 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006512 if (err)
6513 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006514
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006515 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006516
Johan Hedberg66593582014-07-09 12:59:14 +03006517 goto added;
6518 }
6519
Johan Hedberg85813a72015-10-21 18:02:59 +03006520 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006521
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006522 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006523 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006524 else if (cp->action == 0x01)
6525 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006526 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006527 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006528
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006529 /* Kernel internally uses conn_params with resolvable private
6530 * address, but Add Device allows only identity addresses.
6531 * Make sure it is enforced before calling
6532 * hci_conn_params_lookup.
6533 */
6534 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006535 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6536 MGMT_STATUS_INVALID_PARAMS,
6537 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006538 goto unlock;
6539 }
6540
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006541 /* If the connection parameters don't exist for this device,
6542 * they will be created and configured with defaults.
6543 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006544 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006545 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006546 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6547 MGMT_STATUS_FAILED, &cp->addr,
6548 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006549 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006550 } else {
6551 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6552 addr_type);
6553 if (params)
6554 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006555 }
6556
Johan Hedberg51d7a942015-11-11 08:11:18 +02006557 hci_update_background_scan(hdev);
6558
Johan Hedberg66593582014-07-09 12:59:14 +03006559added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006560 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006561 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6562 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006563
Johan Hedberg51d7a942015-11-11 08:11:18 +02006564 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6565 MGMT_STATUS_SUCCESS, &cp->addr,
6566 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006567
6568unlock:
6569 hci_dev_unlock(hdev);
6570 return err;
6571}
6572
Marcel Holtmann8afef092014-06-29 22:28:34 +02006573static void device_removed(struct sock *sk, struct hci_dev *hdev,
6574 bdaddr_t *bdaddr, u8 type)
6575{
6576 struct mgmt_ev_device_removed ev;
6577
6578 bacpy(&ev.addr.bdaddr, bdaddr);
6579 ev.addr.type = type;
6580
6581 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6582}
6583
Marcel Holtmann2faade52014-06-29 19:44:03 +02006584static int remove_device(struct sock *sk, struct hci_dev *hdev,
6585 void *data, u16 len)
6586{
6587 struct mgmt_cp_remove_device *cp = data;
6588 int err;
6589
Marcel Holtmann181d6952020-05-06 09:57:47 +02006590 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006591
6592 hci_dev_lock(hdev);
6593
6594 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006595 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006596 u8 addr_type;
6597
Johan Hedberg66593582014-07-09 12:59:14 +03006598 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006599 err = mgmt_cmd_complete(sk, hdev->id,
6600 MGMT_OP_REMOVE_DEVICE,
6601 MGMT_STATUS_INVALID_PARAMS,
6602 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006603 goto unlock;
6604 }
6605
Johan Hedberg66593582014-07-09 12:59:14 +03006606 if (cp->addr.type == BDADDR_BREDR) {
6607 err = hci_bdaddr_list_del(&hdev->whitelist,
6608 &cp->addr.bdaddr,
6609 cp->addr.type);
6610 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006611 err = mgmt_cmd_complete(sk, hdev->id,
6612 MGMT_OP_REMOVE_DEVICE,
6613 MGMT_STATUS_INVALID_PARAMS,
6614 &cp->addr,
6615 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006616 goto unlock;
6617 }
6618
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006619 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006620
Johan Hedberg66593582014-07-09 12:59:14 +03006621 device_removed(sk, hdev, &cp->addr.bdaddr,
6622 cp->addr.type);
6623 goto complete;
6624 }
6625
Johan Hedberg85813a72015-10-21 18:02:59 +03006626 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006627
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006628 /* Kernel internally uses conn_params with resolvable private
6629 * address, but Remove Device allows only identity addresses.
6630 * Make sure it is enforced before calling
6631 * hci_conn_params_lookup.
6632 */
6633 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006634 err = mgmt_cmd_complete(sk, hdev->id,
6635 MGMT_OP_REMOVE_DEVICE,
6636 MGMT_STATUS_INVALID_PARAMS,
6637 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006638 goto unlock;
6639 }
6640
Johan Hedbergc71593d2014-07-02 17:37:28 +03006641 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6642 addr_type);
6643 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006644 err = mgmt_cmd_complete(sk, hdev->id,
6645 MGMT_OP_REMOVE_DEVICE,
6646 MGMT_STATUS_INVALID_PARAMS,
6647 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006648 goto unlock;
6649 }
6650
Johan Hedberg679d2b62015-10-16 10:07:52 +03006651 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6652 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006653 err = mgmt_cmd_complete(sk, hdev->id,
6654 MGMT_OP_REMOVE_DEVICE,
6655 MGMT_STATUS_INVALID_PARAMS,
6656 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006657 goto unlock;
6658 }
6659
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006660 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006661 list_del(&params->list);
6662 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006663 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006664
6665 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006666 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006667 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006668 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006669
Marcel Holtmann2faade52014-06-29 19:44:03 +02006670 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006671 err = mgmt_cmd_complete(sk, hdev->id,
6672 MGMT_OP_REMOVE_DEVICE,
6673 MGMT_STATUS_INVALID_PARAMS,
6674 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006675 goto unlock;
6676 }
6677
Johan Hedberg66593582014-07-09 12:59:14 +03006678 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6679 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6680 list_del(&b->list);
6681 kfree(b);
6682 }
6683
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006684 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006685
Johan Hedberg19de0822014-07-06 13:06:51 +03006686 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6687 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6688 continue;
6689 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006690 if (p->explicit_connect) {
6691 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6692 continue;
6693 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006694 list_del(&p->action);
6695 list_del(&p->list);
6696 kfree(p);
6697 }
6698
Marcel Holtmann181d6952020-05-06 09:57:47 +02006699 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006700
Johan Hedberg51d7a942015-11-11 08:11:18 +02006701 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006702 }
6703
Johan Hedberg66593582014-07-09 12:59:14 +03006704complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006705 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6706 MGMT_STATUS_SUCCESS, &cp->addr,
6707 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006708unlock:
6709 hci_dev_unlock(hdev);
6710 return err;
6711}
6712
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006713static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6714 u16 len)
6715{
6716 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006717 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6718 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006719 u16 param_count, expected_len;
6720 int i;
6721
6722 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006723 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6724 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006725
6726 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006727 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006728 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6729 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006730 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6731 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006732 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006733
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006734 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006735 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006736 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6737 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6739 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006740 }
6741
Marcel Holtmann181d6952020-05-06 09:57:47 +02006742 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006743
6744 hci_dev_lock(hdev);
6745
6746 hci_conn_params_clear_disabled(hdev);
6747
6748 for (i = 0; i < param_count; i++) {
6749 struct mgmt_conn_param *param = &cp->params[i];
6750 struct hci_conn_params *hci_param;
6751 u16 min, max, latency, timeout;
6752 u8 addr_type;
6753
Marcel Holtmann181d6952020-05-06 09:57:47 +02006754 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6755 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006756
6757 if (param->addr.type == BDADDR_LE_PUBLIC) {
6758 addr_type = ADDR_LE_DEV_PUBLIC;
6759 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6760 addr_type = ADDR_LE_DEV_RANDOM;
6761 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006762 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006763 continue;
6764 }
6765
6766 min = le16_to_cpu(param->min_interval);
6767 max = le16_to_cpu(param->max_interval);
6768 latency = le16_to_cpu(param->latency);
6769 timeout = le16_to_cpu(param->timeout);
6770
Marcel Holtmann181d6952020-05-06 09:57:47 +02006771 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6772 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006773
6774 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006775 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006776 continue;
6777 }
6778
6779 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6780 addr_type);
6781 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006782 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006783 continue;
6784 }
6785
6786 hci_param->conn_min_interval = min;
6787 hci_param->conn_max_interval = max;
6788 hci_param->conn_latency = latency;
6789 hci_param->supervision_timeout = timeout;
6790 }
6791
6792 hci_dev_unlock(hdev);
6793
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006794 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6795 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006796}
6797
Marcel Holtmanndbece372014-07-04 18:11:55 +02006798static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6799 void *data, u16 len)
6800{
6801 struct mgmt_cp_set_external_config *cp = data;
6802 bool changed;
6803 int err;
6804
Marcel Holtmann181d6952020-05-06 09:57:47 +02006805 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006806
6807 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006808 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6809 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006810
6811 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006812 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6813 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006814
6815 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006816 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6817 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006818
6819 hci_dev_lock(hdev);
6820
6821 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006822 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006823 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006824 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006825
6826 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6827 if (err < 0)
6828 goto unlock;
6829
6830 if (!changed)
6831 goto unlock;
6832
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006833 err = new_options(hdev, sk);
6834
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006835 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006836 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006837
Marcel Holtmann516018a2015-03-13 02:11:04 -07006838 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006839 hci_dev_set_flag(hdev, HCI_CONFIG);
6840 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006841
6842 queue_work(hdev->req_workqueue, &hdev->power_on);
6843 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006844 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006845 mgmt_index_added(hdev);
6846 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006847 }
6848
6849unlock:
6850 hci_dev_unlock(hdev);
6851 return err;
6852}
6853
Marcel Holtmann9713c172014-07-06 12:11:15 +02006854static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6855 void *data, u16 len)
6856{
6857 struct mgmt_cp_set_public_address *cp = data;
6858 bool changed;
6859 int err;
6860
Marcel Holtmann181d6952020-05-06 09:57:47 +02006861 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006862
6863 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006864 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6865 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006866
6867 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006868 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6869 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006870
6871 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006872 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6873 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006874
6875 hci_dev_lock(hdev);
6876
6877 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6878 bacpy(&hdev->public_addr, &cp->bdaddr);
6879
6880 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6881 if (err < 0)
6882 goto unlock;
6883
6884 if (!changed)
6885 goto unlock;
6886
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006887 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006888 err = new_options(hdev, sk);
6889
6890 if (is_configured(hdev)) {
6891 mgmt_index_removed(hdev);
6892
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006893 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006894
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006895 hci_dev_set_flag(hdev, HCI_CONFIG);
6896 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006897
6898 queue_work(hdev->req_workqueue, &hdev->power_on);
6899 }
6900
6901unlock:
6902 hci_dev_unlock(hdev);
6903 return err;
6904}
6905
Johan Hedberg40f66c02015-04-07 21:52:22 +03006906static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6907 u16 opcode, struct sk_buff *skb)
6908{
6909 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6910 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6911 u8 *h192, *r192, *h256, *r256;
6912 struct mgmt_pending_cmd *cmd;
6913 u16 eir_len;
6914 int err;
6915
Marcel Holtmann181d6952020-05-06 09:57:47 +02006916 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006917
6918 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6919 if (!cmd)
6920 return;
6921
6922 mgmt_cp = cmd->param;
6923
6924 if (status) {
6925 status = mgmt_status(status);
6926 eir_len = 0;
6927
6928 h192 = NULL;
6929 r192 = NULL;
6930 h256 = NULL;
6931 r256 = NULL;
6932 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6933 struct hci_rp_read_local_oob_data *rp;
6934
6935 if (skb->len != sizeof(*rp)) {
6936 status = MGMT_STATUS_FAILED;
6937 eir_len = 0;
6938 } else {
6939 status = MGMT_STATUS_SUCCESS;
6940 rp = (void *)skb->data;
6941
6942 eir_len = 5 + 18 + 18;
6943 h192 = rp->hash;
6944 r192 = rp->rand;
6945 h256 = NULL;
6946 r256 = NULL;
6947 }
6948 } else {
6949 struct hci_rp_read_local_oob_ext_data *rp;
6950
6951 if (skb->len != sizeof(*rp)) {
6952 status = MGMT_STATUS_FAILED;
6953 eir_len = 0;
6954 } else {
6955 status = MGMT_STATUS_SUCCESS;
6956 rp = (void *)skb->data;
6957
6958 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6959 eir_len = 5 + 18 + 18;
6960 h192 = NULL;
6961 r192 = NULL;
6962 } else {
6963 eir_len = 5 + 18 + 18 + 18 + 18;
6964 h192 = rp->hash192;
6965 r192 = rp->rand192;
6966 }
6967
6968 h256 = rp->hash256;
6969 r256 = rp->rand256;
6970 }
6971 }
6972
6973 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6974 if (!mgmt_rp)
6975 goto done;
6976
6977 if (status)
6978 goto send_rsp;
6979
6980 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6981 hdev->dev_class, 3);
6982
6983 if (h192 && r192) {
6984 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6985 EIR_SSP_HASH_C192, h192, 16);
6986 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6987 EIR_SSP_RAND_R192, r192, 16);
6988 }
6989
6990 if (h256 && r256) {
6991 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6992 EIR_SSP_HASH_C256, h256, 16);
6993 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6994 EIR_SSP_RAND_R256, r256, 16);
6995 }
6996
6997send_rsp:
6998 mgmt_rp->type = mgmt_cp->type;
6999 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7000
7001 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7002 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7003 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7004 if (err < 0 || status)
7005 goto done;
7006
7007 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7008
7009 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7010 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7011 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7012done:
7013 kfree(mgmt_rp);
7014 mgmt_pending_remove(cmd);
7015}
7016
7017static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7018 struct mgmt_cp_read_local_oob_ext_data *cp)
7019{
7020 struct mgmt_pending_cmd *cmd;
7021 struct hci_request req;
7022 int err;
7023
7024 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7025 cp, sizeof(*cp));
7026 if (!cmd)
7027 return -ENOMEM;
7028
7029 hci_req_init(&req, hdev);
7030
7031 if (bredr_sc_enabled(hdev))
7032 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7033 else
7034 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7035
7036 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7037 if (err < 0) {
7038 mgmt_pending_remove(cmd);
7039 return err;
7040 }
7041
7042 return 0;
7043}
7044
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007045static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7046 void *data, u16 data_len)
7047{
7048 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7049 struct mgmt_rp_read_local_oob_ext_data *rp;
7050 size_t rp_len;
7051 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007052 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007053 int err;
7054
Marcel Holtmann181d6952020-05-06 09:57:47 +02007055 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007056
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007057 if (hdev_is_powered(hdev)) {
7058 switch (cp->type) {
7059 case BIT(BDADDR_BREDR):
7060 status = mgmt_bredr_support(hdev);
7061 if (status)
7062 eir_len = 0;
7063 else
7064 eir_len = 5;
7065 break;
7066 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7067 status = mgmt_le_support(hdev);
7068 if (status)
7069 eir_len = 0;
7070 else
7071 eir_len = 9 + 3 + 18 + 18 + 3;
7072 break;
7073 default:
7074 status = MGMT_STATUS_INVALID_PARAMS;
7075 eir_len = 0;
7076 break;
7077 }
7078 } else {
7079 status = MGMT_STATUS_NOT_POWERED;
7080 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007081 }
7082
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007083 rp_len = sizeof(*rp) + eir_len;
7084 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007085 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007086 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007087
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007088 if (status)
7089 goto complete;
7090
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007091 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007092
7093 eir_len = 0;
7094 switch (cp->type) {
7095 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007096 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7097 err = read_local_ssp_oob_req(hdev, sk, cp);
7098 hci_dev_unlock(hdev);
7099 if (!err)
7100 goto done;
7101
7102 status = MGMT_STATUS_FAILED;
7103 goto complete;
7104 } else {
7105 eir_len = eir_append_data(rp->eir, eir_len,
7106 EIR_CLASS_OF_DEV,
7107 hdev->dev_class, 3);
7108 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007109 break;
7110 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007111 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7112 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007113 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007114 status = MGMT_STATUS_FAILED;
7115 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007116 }
7117
Marcel Holtmanne2135682015-04-02 12:00:58 -07007118 /* This should return the active RPA, but since the RPA
7119 * is only programmed on demand, it is really hard to fill
7120 * this in at the moment. For now disallow retrieving
7121 * local out-of-band data when privacy is in use.
7122 *
7123 * Returning the identity address will not help here since
7124 * pairing happens before the identity resolving key is
7125 * known and thus the connection establishment happens
7126 * based on the RPA and not the identity address.
7127 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007128 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007129 hci_dev_unlock(hdev);
7130 status = MGMT_STATUS_REJECTED;
7131 goto complete;
7132 }
7133
7134 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7135 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7136 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7137 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007138 memcpy(addr, &hdev->static_addr, 6);
7139 addr[6] = 0x01;
7140 } else {
7141 memcpy(addr, &hdev->bdaddr, 6);
7142 addr[6] = 0x00;
7143 }
7144
7145 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7146 addr, sizeof(addr));
7147
7148 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7149 role = 0x02;
7150 else
7151 role = 0x01;
7152
7153 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7154 &role, sizeof(role));
7155
Marcel Holtmann5082a592015-03-16 12:39:00 -07007156 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7157 eir_len = eir_append_data(rp->eir, eir_len,
7158 EIR_LE_SC_CONFIRM,
7159 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007160
Marcel Holtmann5082a592015-03-16 12:39:00 -07007161 eir_len = eir_append_data(rp->eir, eir_len,
7162 EIR_LE_SC_RANDOM,
7163 rand, sizeof(rand));
7164 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007165
Johan Hedbergf2252572015-11-18 12:49:20 +02007166 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007167
7168 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7169 flags |= LE_AD_NO_BREDR;
7170
7171 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7172 &flags, sizeof(flags));
7173 break;
7174 }
7175
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007176 hci_dev_unlock(hdev);
7177
Marcel Holtmann72000df2015-03-16 16:11:21 -07007178 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7179
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007180 status = MGMT_STATUS_SUCCESS;
7181
7182complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007183 rp->type = cp->type;
7184 rp->eir_len = cpu_to_le16(eir_len);
7185
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007186 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007187 status, rp, sizeof(*rp) + eir_len);
7188 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007189 goto done;
7190
7191 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7192 rp, sizeof(*rp) + eir_len,
7193 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007194
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007195done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007196 kfree(rp);
7197
7198 return err;
7199}
7200
Arman Uguray089fa8c2015-03-25 18:53:45 -07007201static u32 get_supported_adv_flags(struct hci_dev *hdev)
7202{
7203 u32 flags = 0;
7204
7205 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7206 flags |= MGMT_ADV_FLAG_DISCOV;
7207 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7208 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007209 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007210 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007211
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307212 /* In extended adv TX_POWER returned from Set Adv Param
7213 * will be always valid.
7214 */
7215 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7216 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007217 flags |= MGMT_ADV_FLAG_TX_POWER;
7218
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307219 if (ext_adv_capable(hdev)) {
7220 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007221 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7222 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307223
7224 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7225 flags |= MGMT_ADV_FLAG_SEC_2M;
7226
7227 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7228 flags |= MGMT_ADV_FLAG_SEC_CODED;
7229 }
7230
Arman Uguray089fa8c2015-03-25 18:53:45 -07007231 return flags;
7232}
7233
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007234static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7235 void *data, u16 data_len)
7236{
7237 struct mgmt_rp_read_adv_features *rp;
7238 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007239 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007240 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007241 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007242 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007243
Marcel Holtmann181d6952020-05-06 09:57:47 +02007244 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007245
Arman Uguray089fa8c2015-03-25 18:53:45 -07007246 if (!lmp_le_capable(hdev))
7247 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7248 MGMT_STATUS_REJECTED);
7249
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307250 /* Enabling the experimental LL Privay support disables support for
7251 * advertising.
7252 */
7253 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7254 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7255 MGMT_STATUS_NOT_SUPPORTED);
7256
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007257 hci_dev_lock(hdev);
7258
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007259 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007260 rp = kmalloc(rp_len, GFP_ATOMIC);
7261 if (!rp) {
7262 hci_dev_unlock(hdev);
7263 return -ENOMEM;
7264 }
7265
Arman Uguray089fa8c2015-03-25 18:53:45 -07007266 supported_flags = get_supported_adv_flags(hdev);
7267
7268 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007269 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7270 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007271 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007272 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007273
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007274 instance = rp->instance;
7275 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7276 *instance = adv_instance->instance;
7277 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007278 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007279
7280 hci_dev_unlock(hdev);
7281
7282 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7283 MGMT_STATUS_SUCCESS, rp, rp_len);
7284
7285 kfree(rp);
7286
7287 return err;
7288}
7289
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007290static u8 calculate_name_len(struct hci_dev *hdev)
7291{
7292 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7293
7294 return append_local_name(hdev, buf, 0);
7295}
7296
7297static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7298 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007299{
Arman Uguray4117ed72015-03-23 15:57:14 -07007300 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007301
Marcel Holtmann31a32482015-11-19 16:16:42 +01007302 if (is_adv_data) {
7303 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7304 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007305 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007306 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007307
Szymon Janc2bb368702016-09-18 12:50:05 +02007308 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007309 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007310 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007311 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007312 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007313
Szymon Janc2bb368702016-09-18 12:50:05 +02007314 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007315 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007316 }
7317
Szymon Janc2bb368702016-09-18 12:50:05 +02007318 return max_len;
7319}
7320
7321static bool flags_managed(u32 adv_flags)
7322{
7323 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7324 MGMT_ADV_FLAG_LIMITED_DISCOV |
7325 MGMT_ADV_FLAG_MANAGED_FLAGS);
7326}
7327
7328static bool tx_power_managed(u32 adv_flags)
7329{
7330 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7331}
7332
7333static bool name_managed(u32 adv_flags)
7334{
7335 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7336}
7337
7338static bool appearance_managed(u32 adv_flags)
7339{
7340 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7341}
7342
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007343static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7344 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007345{
7346 int i, cur_len;
7347 u8 max_len;
7348
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007349 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007350
Arman Uguray4117ed72015-03-23 15:57:14 -07007351 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007352 return false;
7353
Arman Uguray4117ed72015-03-23 15:57:14 -07007354 /* Make sure that the data is correctly formatted. */
7355 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7356 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007357
Luiz Augusto von Dentza2dcad02021-05-28 11:45:02 -07007358 if (!cur_len)
7359 continue;
7360
Szymon Janc9c9db782016-09-18 12:50:06 +02007361 if (data[i + 1] == EIR_FLAGS &&
7362 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007363 return false;
7364
Szymon Janc2bb368702016-09-18 12:50:05 +02007365 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7366 return false;
7367
7368 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7369 return false;
7370
7371 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7372 return false;
7373
7374 if (data[i + 1] == EIR_APPEARANCE &&
7375 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007376 return false;
7377
Arman Uguray24b4f382015-03-23 15:57:12 -07007378 /* If the current field length would exceed the total data
7379 * length, then it's invalid.
7380 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007381 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007382 return false;
7383 }
7384
7385 return true;
7386}
7387
Arman Uguray24b4f382015-03-23 15:57:12 -07007388static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7389 u16 opcode)
7390{
7391 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007392 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007393 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007394 struct adv_info *adv_instance, *n;
7395 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007396
Marcel Holtmann181d6952020-05-06 09:57:47 +02007397 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007398
7399 hci_dev_lock(hdev);
7400
7401 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7402
Florian Grandelfffd38b2015-06-18 03:16:47 +02007403 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7404 if (!adv_instance->pending)
7405 continue;
7406
7407 if (!status) {
7408 adv_instance->pending = false;
7409 continue;
7410 }
7411
7412 instance = adv_instance->instance;
7413
7414 if (hdev->cur_adv_instance == instance)
7415 cancel_adv_timeout(hdev);
7416
7417 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007418 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007419 }
7420
7421 if (!cmd)
7422 goto unlock;
7423
Florian Grandelfffd38b2015-06-18 03:16:47 +02007424 cp = cmd->param;
7425 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007426
7427 if (status)
7428 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7429 mgmt_status(status));
7430 else
7431 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7432 mgmt_status(status), &rp, sizeof(rp));
7433
7434 mgmt_pending_remove(cmd);
7435
7436unlock:
7437 hci_dev_unlock(hdev);
7438}
7439
7440static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7441 void *data, u16 data_len)
7442{
7443 struct mgmt_cp_add_advertising *cp = data;
7444 struct mgmt_rp_add_advertising rp;
7445 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307446 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007447 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007448 u16 timeout, duration;
7449 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7450 u8 schedule_instance = 0;
7451 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007452 int err;
7453 struct mgmt_pending_cmd *cmd;
7454 struct hci_request req;
7455
Marcel Holtmann181d6952020-05-06 09:57:47 +02007456 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007457
7458 status = mgmt_le_support(hdev);
7459 if (status)
7460 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7461 status);
7462
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307463 /* Enabling the experimental LL Privay support disables support for
7464 * advertising.
7465 */
7466 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
Tedd Ho-Jeong An61b1db22021-07-26 13:22:36 -07007467 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307468 MGMT_STATUS_NOT_SUPPORTED);
7469
Daniel Winkler87597482020-08-25 16:31:50 -07007470 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007471 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7472 MGMT_STATUS_INVALID_PARAMS);
7473
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007474 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7475 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7476 MGMT_STATUS_INVALID_PARAMS);
7477
Arman Uguray24b4f382015-03-23 15:57:12 -07007478 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007479 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007480 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007481
Florian Grandelfffd38b2015-06-18 03:16:47 +02007482 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307483 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007484 */
7485 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307486 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7487 if (flags & ~supported_flags ||
7488 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007489 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7490 MGMT_STATUS_INVALID_PARAMS);
7491
7492 hci_dev_lock(hdev);
7493
Arman Uguray912098a2015-03-23 15:57:15 -07007494 if (timeout && !hdev_is_powered(hdev)) {
7495 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7496 MGMT_STATUS_REJECTED);
7497 goto unlock;
7498 }
7499
Arman Uguray24b4f382015-03-23 15:57:12 -07007500 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007501 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007502 pending_find(MGMT_OP_SET_LE, hdev)) {
7503 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7504 MGMT_STATUS_BUSY);
7505 goto unlock;
7506 }
7507
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007508 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7509 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007510 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007511 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7512 MGMT_STATUS_INVALID_PARAMS);
7513 goto unlock;
7514 }
7515
Florian Grandelfffd38b2015-06-18 03:16:47 +02007516 err = hci_add_adv_instance(hdev, cp->instance, flags,
7517 cp->adv_data_len, cp->data,
7518 cp->scan_rsp_len,
7519 cp->data + cp->adv_data_len,
7520 timeout, duration);
7521 if (err < 0) {
7522 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7523 MGMT_STATUS_FAILED);
7524 goto unlock;
7525 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007526
Florian Grandelfffd38b2015-06-18 03:16:47 +02007527 /* Only trigger an advertising added event if a new instance was
7528 * actually added.
7529 */
7530 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007531 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007532
Florian Grandelfffd38b2015-06-18 03:16:47 +02007533 if (hdev->cur_adv_instance == cp->instance) {
7534 /* If the currently advertised instance is being changed then
7535 * cancel the current advertising and schedule the next
7536 * instance. If there is only one instance then the overridden
7537 * advertising data will be visible right away.
7538 */
7539 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007540
Florian Grandelfffd38b2015-06-18 03:16:47 +02007541 next_instance = hci_get_next_instance(hdev, cp->instance);
7542 if (next_instance)
7543 schedule_instance = next_instance->instance;
7544 } else if (!hdev->adv_instance_timeout) {
7545 /* Immediately advertise the new instance if no other
7546 * instance is currently being advertised.
7547 */
7548 schedule_instance = cp->instance;
7549 }
Arman Uguray912098a2015-03-23 15:57:15 -07007550
Florian Grandelfffd38b2015-06-18 03:16:47 +02007551 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7552 * there is no instance to be advertised then we have no HCI
7553 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007554 */
7555 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007556 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7557 !schedule_instance) {
7558 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007559 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7560 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7561 goto unlock;
7562 }
7563
7564 /* We're good to go, update advertising data, parameters, and start
7565 * advertising.
7566 */
7567 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7568 data_len);
7569 if (!cmd) {
7570 err = -ENOMEM;
7571 goto unlock;
7572 }
7573
7574 hci_req_init(&req, hdev);
7575
Johan Hedbergf2252572015-11-18 12:49:20 +02007576 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007577
Florian Grandelfffd38b2015-06-18 03:16:47 +02007578 if (!err)
7579 err = hci_req_run(&req, add_advertising_complete);
7580
Joseph Hwang72da7b22020-03-10 09:31:50 -07007581 if (err < 0) {
7582 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7583 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007584 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007585 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007586
7587unlock:
7588 hci_dev_unlock(hdev);
7589
7590 return err;
7591}
7592
Arman Ugurayda9293352015-03-23 15:57:13 -07007593static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7594 u16 opcode)
7595{
7596 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007597 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007598 struct mgmt_rp_remove_advertising rp;
7599
Marcel Holtmann181d6952020-05-06 09:57:47 +02007600 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007601
7602 hci_dev_lock(hdev);
7603
7604 /* A failure status here only means that we failed to disable
7605 * advertising. Otherwise, the advertising instance has been removed,
7606 * so report success.
7607 */
7608 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7609 if (!cmd)
7610 goto unlock;
7611
Florian Grandel01948332015-06-18 03:16:48 +02007612 cp = cmd->param;
7613 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007614
7615 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7616 &rp, sizeof(rp));
7617 mgmt_pending_remove(cmd);
7618
7619unlock:
7620 hci_dev_unlock(hdev);
7621}
7622
7623static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7624 void *data, u16 data_len)
7625{
7626 struct mgmt_cp_remove_advertising *cp = data;
7627 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007628 struct mgmt_pending_cmd *cmd;
7629 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007630 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007631
Marcel Holtmann181d6952020-05-06 09:57:47 +02007632 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007633
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307634 /* Enabling the experimental LL Privay support disables support for
7635 * advertising.
7636 */
7637 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7638 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7639 MGMT_STATUS_NOT_SUPPORTED);
7640
Arman Ugurayda9293352015-03-23 15:57:13 -07007641 hci_dev_lock(hdev);
7642
Johan Hedberg952497b2015-06-18 21:05:31 +03007643 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007644 err = mgmt_cmd_status(sk, hdev->id,
7645 MGMT_OP_REMOVE_ADVERTISING,
7646 MGMT_STATUS_INVALID_PARAMS);
7647 goto unlock;
7648 }
7649
Arman Ugurayda9293352015-03-23 15:57:13 -07007650 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7651 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7652 pending_find(MGMT_OP_SET_LE, hdev)) {
7653 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7654 MGMT_STATUS_BUSY);
7655 goto unlock;
7656 }
7657
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007658 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007659 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7660 MGMT_STATUS_INVALID_PARAMS);
7661 goto unlock;
7662 }
7663
Florian Grandel01948332015-06-18 03:16:48 +02007664 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007665
Daniel Winkler37adf702020-07-14 14:16:00 -07007666 /* If we use extended advertising, instance is disabled and removed */
7667 if (ext_adv_capable(hdev)) {
7668 __hci_req_disable_ext_adv_instance(&req, cp->instance);
7669 __hci_req_remove_ext_adv_instance(&req, cp->instance);
7670 }
7671
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007672 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007673
Florian Grandel01948332015-06-18 03:16:48 +02007674 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007675 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007676
Florian Grandel01948332015-06-18 03:16:48 +02007677 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7678 * flag is set or the device isn't powered then we have no HCI
7679 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007680 */
Florian Grandel01948332015-06-18 03:16:48 +02007681 if (skb_queue_empty(&req.cmd_q) ||
7682 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007683 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307684 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007685 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007686 err = mgmt_cmd_complete(sk, hdev->id,
7687 MGMT_OP_REMOVE_ADVERTISING,
7688 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7689 goto unlock;
7690 }
7691
7692 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7693 data_len);
7694 if (!cmd) {
7695 err = -ENOMEM;
7696 goto unlock;
7697 }
7698
Arman Ugurayda9293352015-03-23 15:57:13 -07007699 err = hci_req_run(&req, remove_advertising_complete);
7700 if (err < 0)
7701 mgmt_pending_remove(cmd);
7702
7703unlock:
7704 hci_dev_unlock(hdev);
7705
7706 return err;
7707}
7708
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007709static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7710 void *data, u16 data_len)
7711{
7712 struct mgmt_cp_get_adv_size_info *cp = data;
7713 struct mgmt_rp_get_adv_size_info rp;
7714 u32 flags, supported_flags;
7715 int err;
7716
Marcel Holtmann181d6952020-05-06 09:57:47 +02007717 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007718
7719 if (!lmp_le_capable(hdev))
7720 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7721 MGMT_STATUS_REJECTED);
7722
Daniel Winkler87597482020-08-25 16:31:50 -07007723 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007724 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7725 MGMT_STATUS_INVALID_PARAMS);
7726
7727 flags = __le32_to_cpu(cp->flags);
7728
7729 /* The current implementation only supports a subset of the specified
7730 * flags.
7731 */
7732 supported_flags = get_supported_adv_flags(hdev);
7733 if (flags & ~supported_flags)
7734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7735 MGMT_STATUS_INVALID_PARAMS);
7736
7737 rp.instance = cp->instance;
7738 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007739 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7740 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007741
7742 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7743 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7744
7745 return err;
7746}
7747
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007748static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007749 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007750 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007751 HCI_MGMT_NO_HDEV |
7752 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007753 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007754 HCI_MGMT_NO_HDEV |
7755 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007756 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007757 HCI_MGMT_NO_HDEV |
7758 HCI_MGMT_UNTRUSTED },
7759 { read_controller_info, MGMT_READ_INFO_SIZE,
7760 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007761 { set_powered, MGMT_SETTING_SIZE },
7762 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7763 { set_connectable, MGMT_SETTING_SIZE },
7764 { set_fast_connectable, MGMT_SETTING_SIZE },
7765 { set_bondable, MGMT_SETTING_SIZE },
7766 { set_link_security, MGMT_SETTING_SIZE },
7767 { set_ssp, MGMT_SETTING_SIZE },
7768 { set_hs, MGMT_SETTING_SIZE },
7769 { set_le, MGMT_SETTING_SIZE },
7770 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7771 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7772 { add_uuid, MGMT_ADD_UUID_SIZE },
7773 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007774 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7775 HCI_MGMT_VAR_LEN },
7776 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7777 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007778 { disconnect, MGMT_DISCONNECT_SIZE },
7779 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7780 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7781 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7782 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7783 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7784 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7785 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7786 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7787 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7788 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7789 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007790 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7791 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7792 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007793 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7794 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7795 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7796 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7797 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7798 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7799 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7800 { set_advertising, MGMT_SETTING_SIZE },
7801 { set_bredr, MGMT_SETTING_SIZE },
7802 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7803 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7804 { set_secure_conn, MGMT_SETTING_SIZE },
7805 { set_debug_keys, MGMT_SETTING_SIZE },
7806 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007807 { load_irks, MGMT_LOAD_IRKS_SIZE,
7808 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007809 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7810 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7811 { add_device, MGMT_ADD_DEVICE_SIZE },
7812 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007813 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7814 HCI_MGMT_VAR_LEN },
7815 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007816 HCI_MGMT_NO_HDEV |
7817 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007818 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007819 HCI_MGMT_UNCONFIGURED |
7820 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007821 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7822 HCI_MGMT_UNCONFIGURED },
7823 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7824 HCI_MGMT_UNCONFIGURED },
7825 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7826 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007827 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007828 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007829 HCI_MGMT_NO_HDEV |
7830 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007831 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007832 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7833 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007834 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007835 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007836 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007837 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7838 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007839 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307840 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307841 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007842 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7843 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007844 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007845 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7846 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007847 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7848 HCI_MGMT_UNTRUSTED |
7849 HCI_MGMT_HDEV_OPTIONAL },
7850 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7851 HCI_MGMT_VAR_LEN |
7852 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007853 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7854 HCI_MGMT_UNTRUSTED },
7855 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7856 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007857 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7858 HCI_MGMT_UNTRUSTED },
7859 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7860 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007861 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7862 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007863 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02007864 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
7865 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02007866 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007867};
7868
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007869void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007870{
Marcel Holtmannced85542015-03-14 19:27:56 -07007871 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007872
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007873 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7874 return;
7875
Marcel Holtmannf9207332015-03-14 19:27:55 -07007876 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007877 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007878 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7879 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7880 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007881 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007882 } else {
7883 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7884 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007885 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007886 }
7887 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007888 case HCI_AMP:
7889 ev.type = 0x02;
7890 break;
7891 default:
7892 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007893 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007894
7895 ev.bus = hdev->bus;
7896
7897 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7898 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007899}
7900
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007901void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007902{
Marcel Holtmannced85542015-03-14 19:27:56 -07007903 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007904 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007905
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007906 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7907 return;
7908
Marcel Holtmannf9207332015-03-14 19:27:55 -07007909 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007910 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007911 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007912
Marcel Holtmannf9207332015-03-14 19:27:55 -07007913 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7914 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7915 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007916 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007917 } else {
7918 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7919 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007920 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007921 }
7922 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007923 case HCI_AMP:
7924 ev.type = 0x02;
7925 break;
7926 default:
7927 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007928 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007929
7930 ev.bus = hdev->bus;
7931
7932 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7933 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007934}
7935
Andre Guedes6046dc32014-02-26 20:21:51 -03007936/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007937static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007938{
7939 struct hci_conn_params *p;
7940
7941 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007942 /* Needed for AUTO_OFF case where might not "really"
7943 * have been powered off.
7944 */
7945 list_del_init(&p->action);
7946
7947 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007948 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007949 case HCI_AUTO_CONN_ALWAYS:
7950 list_add(&p->action, &hdev->pend_le_conns);
7951 break;
7952 case HCI_AUTO_CONN_REPORT:
7953 list_add(&p->action, &hdev->pend_le_reports);
7954 break;
7955 default:
7956 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007957 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007958 }
7959}
7960
Johan Hedberg2ff13892015-11-25 16:15:44 +02007961void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007962{
7963 struct cmd_lookup match = { NULL, hdev };
7964
Marcel Holtmann181d6952020-05-06 09:57:47 +02007965 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007966
Johan Hedberg2ff13892015-11-25 16:15:44 +02007967 hci_dev_lock(hdev);
7968
7969 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007970 restart_le_actions(hdev);
7971 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007972 }
7973
Johan Hedberg229ab392013-03-15 17:06:53 -05007974 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7975
7976 new_settings(hdev, match.sk);
7977
Johan Hedberg229ab392013-03-15 17:06:53 -05007978 if (match.sk)
7979 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007980
7981 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007982}
7983
Johan Hedberg2ff13892015-11-25 16:15:44 +02007984void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007985{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007986 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007987 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007988
Johan Hedberg229ab392013-03-15 17:06:53 -05007989 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007990
7991 /* If the power off is because of hdev unregistration let
7992 * use the appropriate INVALID_INDEX status. Otherwise use
7993 * NOT_POWERED. We cover both scenarios here since later in
7994 * mgmt_index_removed() any hci_conn callbacks will have already
7995 * been triggered, potentially causing misleading DISCONNECTED
7996 * status responses.
7997 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007998 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007999 status = MGMT_STATUS_INVALID_INDEX;
8000 else
8001 status = MGMT_STATUS_NOT_POWERED;
8002
8003 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008004
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008005 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008006 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8007 zero_cod, sizeof(zero_cod),
8008 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008009 ext_info_changed(hdev, NULL);
8010 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008011
Johan Hedberg2ff13892015-11-25 16:15:44 +02008012 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008013
8014 if (match.sk)
8015 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008016}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008017
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008018void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008020 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008021 u8 status;
8022
Johan Hedberg333ae952015-03-17 13:48:47 +02008023 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008024 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008025 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008026
8027 if (err == -ERFKILL)
8028 status = MGMT_STATUS_RFKILLED;
8029 else
8030 status = MGMT_STATUS_FAILED;
8031
Johan Hedberga69e8372015-03-06 21:08:53 +02008032 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008033
8034 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008035}
8036
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008037void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8038 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008039{
Johan Hedberg86742e12011-11-07 23:13:38 +02008040 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008041
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008042 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008043
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008044 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008045 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008046 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008047 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008048 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008049 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008050
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008051 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008052}
Johan Hedbergf7520542011-01-20 12:34:39 +02008053
Johan Hedbergd7b25452014-05-23 13:19:53 +03008054static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8055{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008056 switch (ltk->type) {
8057 case SMP_LTK:
8058 case SMP_LTK_SLAVE:
8059 if (ltk->authenticated)
8060 return MGMT_LTK_AUTHENTICATED;
8061 return MGMT_LTK_UNAUTHENTICATED;
8062 case SMP_LTK_P256:
8063 if (ltk->authenticated)
8064 return MGMT_LTK_P256_AUTH;
8065 return MGMT_LTK_P256_UNAUTH;
8066 case SMP_LTK_P256_DEBUG:
8067 return MGMT_LTK_P256_DEBUG;
8068 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008069
8070 return MGMT_LTK_UNAUTHENTICATED;
8071}
8072
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008073void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008074{
8075 struct mgmt_ev_new_long_term_key ev;
8076
8077 memset(&ev, 0, sizeof(ev));
8078
Marcel Holtmann5192d302014-02-19 17:11:58 -08008079 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008080 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008081 * to store long term keys. Their addresses will change the
8082 * next time around.
8083 *
8084 * Only when a remote device provides an identity address
8085 * make sure the long term key is stored. If the remote
8086 * identity is known, the long term keys are internally
8087 * mapped to the identity address. So allow static random
8088 * and public addresses here.
8089 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008090 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8091 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8092 ev.store_hint = 0x00;
8093 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008094 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008095
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008096 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008097 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008098 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008099 ev.key.enc_size = key->enc_size;
8100 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008101 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008102
Johan Hedberg2ceba532014-06-16 19:25:16 +03008103 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008104 ev.key.master = 1;
8105
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008106 /* Make sure we copy only the significant bytes based on the
8107 * encryption key size, and set the rest of the value to zeroes.
8108 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008109 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008110 memset(ev.key.val + key->enc_size, 0,
8111 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008112
Marcel Holtmann083368f2013-10-15 14:26:29 -07008113 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008114}
8115
Johan Hedbergcad20c22015-10-12 13:36:19 +02008116void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008117{
8118 struct mgmt_ev_new_irk ev;
8119
8120 memset(&ev, 0, sizeof(ev));
8121
Johan Hedbergcad20c22015-10-12 13:36:19 +02008122 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008123
Johan Hedberg95fbac82014-02-19 15:18:31 +02008124 bacpy(&ev.rpa, &irk->rpa);
8125 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8126 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8127 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8128
8129 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8130}
8131
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008132void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8133 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008134{
8135 struct mgmt_ev_new_csrk ev;
8136
8137 memset(&ev, 0, sizeof(ev));
8138
8139 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008140 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008141 * to store signature resolving keys. Their addresses will change
8142 * the next time around.
8143 *
8144 * Only when a remote device provides an identity address
8145 * make sure the signature resolving key is stored. So allow
8146 * static random and public addresses here.
8147 */
8148 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8149 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8150 ev.store_hint = 0x00;
8151 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008152 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008153
8154 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8155 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008156 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008157 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8158
8159 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8160}
8161
Andre Guedesffb5a8272014-07-01 18:10:11 -03008162void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008163 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8164 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008165{
8166 struct mgmt_ev_new_conn_param ev;
8167
Johan Hedbergc103aea2014-07-02 17:37:34 +03008168 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8169 return;
8170
Andre Guedesffb5a8272014-07-01 18:10:11 -03008171 memset(&ev, 0, sizeof(ev));
8172 bacpy(&ev.addr.bdaddr, bdaddr);
8173 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008174 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008175 ev.min_interval = cpu_to_le16(min_interval);
8176 ev.max_interval = cpu_to_le16(max_interval);
8177 ev.latency = cpu_to_le16(latency);
8178 ev.timeout = cpu_to_le16(timeout);
8179
8180 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8181}
8182
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008183void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
8184 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008185{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008186 char buf[512];
8187 struct mgmt_ev_device_connected *ev = (void *) buf;
8188 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008189
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008190 bacpy(&ev->addr.bdaddr, &conn->dst);
8191 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008192
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008193 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008194
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008195 /* We must ensure that the EIR Data fields are ordered and
8196 * unique. Keep it simple for now and avoid the problem by not
8197 * adding any BR/EDR data to the LE adv.
8198 */
8199 if (conn->le_adv_data_len > 0) {
8200 memcpy(&ev->eir[eir_len],
8201 conn->le_adv_data, conn->le_adv_data_len);
8202 eir_len = conn->le_adv_data_len;
8203 } else {
8204 if (name_len > 0)
8205 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8206 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008207
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008208 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008209 eir_len = eir_append_data(ev->eir, eir_len,
8210 EIR_CLASS_OF_DEV,
8211 conn->dev_class, 3);
8212 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008213
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008214 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008215
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008216 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8217 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008218}
8219
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008220static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008221{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008222 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008223
Johan Hedbergf5818c22014-12-05 13:36:02 +02008224 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008225
8226 *sk = cmd->sk;
8227 sock_hold(*sk);
8228
Johan Hedberga664b5b2011-02-19 12:06:02 -03008229 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008230}
8231
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008232static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008233{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008234 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008235 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008236
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008237 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8238
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008239 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008240 mgmt_pending_remove(cmd);
8241}
8242
Johan Hedberg84c61d92014-08-01 11:13:30 +03008243bool mgmt_powering_down(struct hci_dev *hdev)
8244{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008245 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008246 struct mgmt_mode *cp;
8247
Johan Hedberg333ae952015-03-17 13:48:47 +02008248 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008249 if (!cmd)
8250 return false;
8251
8252 cp = cmd->param;
8253 if (!cp->val)
8254 return true;
8255
8256 return false;
8257}
8258
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008259void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008260 u8 link_type, u8 addr_type, u8 reason,
8261 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008262{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008263 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008264 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008265
Johan Hedberg84c61d92014-08-01 11:13:30 +03008266 /* The connection is still in hci_conn_hash so test for 1
8267 * instead of 0 to know if this is the last one.
8268 */
8269 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8270 cancel_delayed_work(&hdev->power_off);
8271 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008272 }
8273
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008274 if (!mgmt_connected)
8275 return;
8276
Andre Guedes57eb7762013-10-30 19:01:41 -03008277 if (link_type != ACL_LINK && link_type != LE_LINK)
8278 return;
8279
Johan Hedberg744cf192011-11-08 20:40:14 +02008280 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008281
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008282 bacpy(&ev.addr.bdaddr, bdaddr);
8283 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8284 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008285
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07008286 /* Report disconnects due to suspend */
8287 if (hdev->suspended)
8288 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
8289
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008290 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008291
8292 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008293 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008294
Johan Hedberg124f6e32012-02-09 13:50:12 +02008295 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008296 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008297}
8298
Marcel Holtmann78929242013-10-06 23:55:47 -07008299void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8300 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008301{
Andre Guedes3655bba2013-10-30 19:01:40 -03008302 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8303 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008304 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008305
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008306 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8307 hdev);
8308
Johan Hedberg333ae952015-03-17 13:48:47 +02008309 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008310 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008311 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008312
Andre Guedes3655bba2013-10-30 19:01:40 -03008313 cp = cmd->param;
8314
8315 if (bacmp(bdaddr, &cp->addr.bdaddr))
8316 return;
8317
8318 if (cp->addr.type != bdaddr_type)
8319 return;
8320
Johan Hedbergf5818c22014-12-05 13:36:02 +02008321 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008322 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008323}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008324
Marcel Holtmann445608d2013-10-06 23:55:48 -07008325void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8326 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008327{
8328 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008329
Johan Hedberg84c61d92014-08-01 11:13:30 +03008330 /* The connection is still in hci_conn_hash so test for 1
8331 * instead of 0 to know if this is the last one.
8332 */
8333 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8334 cancel_delayed_work(&hdev->power_off);
8335 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008336 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008337
Johan Hedberg4c659c32011-11-07 23:13:39 +02008338 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008339 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008340 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008341
Marcel Holtmann445608d2013-10-06 23:55:48 -07008342 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008343}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008344
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008345void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008346{
8347 struct mgmt_ev_pin_code_request ev;
8348
Johan Hedbergd8457692012-02-17 14:24:57 +02008349 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008350 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008351 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008352
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008353 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008354}
8355
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008356void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8357 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008358{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008359 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008360
Johan Hedberg333ae952015-03-17 13:48:47 +02008361 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008362 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008363 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008364
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008365 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008366 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008367}
8368
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008369void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8370 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008371{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008372 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008373
Johan Hedberg333ae952015-03-17 13:48:47 +02008374 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008375 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008376 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008377
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008378 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008379 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008380}
Johan Hedberga5c29682011-02-19 12:05:57 -03008381
Johan Hedberg744cf192011-11-08 20:40:14 +02008382int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008383 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008384 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008385{
8386 struct mgmt_ev_user_confirm_request ev;
8387
Marcel Holtmann181d6952020-05-06 09:57:47 +02008388 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008389
Johan Hedberg272d90d2012-02-09 15:26:12 +02008390 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008391 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008392 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008393 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008394
Johan Hedberg744cf192011-11-08 20:40:14 +02008395 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008396 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008397}
8398
Johan Hedberg272d90d2012-02-09 15:26:12 +02008399int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008400 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008401{
8402 struct mgmt_ev_user_passkey_request ev;
8403
Marcel Holtmann181d6952020-05-06 09:57:47 +02008404 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008405
Johan Hedberg272d90d2012-02-09 15:26:12 +02008406 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008407 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008408
8409 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008410 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008411}
8412
Brian Gix0df4c182011-11-16 13:53:13 -08008413static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008414 u8 link_type, u8 addr_type, u8 status,
8415 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008416{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008417 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008418
Johan Hedberg333ae952015-03-17 13:48:47 +02008419 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008420 if (!cmd)
8421 return -ENOENT;
8422
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008423 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008424 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008425
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008426 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008427}
8428
Johan Hedberg744cf192011-11-08 20:40:14 +02008429int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008430 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008431{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008432 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008433 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008434}
8435
Johan Hedberg272d90d2012-02-09 15:26:12 +02008436int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008437 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008438{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008439 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008440 status,
8441 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008442}
Johan Hedberg2a611692011-02-19 12:06:00 -03008443
Brian Gix604086b2011-11-23 08:28:33 -08008444int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008445 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008446{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008447 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008448 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008449}
8450
Johan Hedberg272d90d2012-02-09 15:26:12 +02008451int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008452 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008453{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008454 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008455 status,
8456 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008457}
8458
Johan Hedberg92a25252012-09-06 18:39:26 +03008459int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8460 u8 link_type, u8 addr_type, u32 passkey,
8461 u8 entered)
8462{
8463 struct mgmt_ev_passkey_notify ev;
8464
Marcel Holtmann181d6952020-05-06 09:57:47 +02008465 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008466
8467 bacpy(&ev.addr.bdaddr, bdaddr);
8468 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8469 ev.passkey = __cpu_to_le32(passkey);
8470 ev.entered = entered;
8471
8472 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8473}
8474
Johan Hedberge1e930f2014-09-08 17:09:49 -07008475void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008476{
8477 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008478 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008479 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008480
Johan Hedberge1e930f2014-09-08 17:09:49 -07008481 bacpy(&ev.addr.bdaddr, &conn->dst);
8482 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8483 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008484
Johan Hedberge1e930f2014-09-08 17:09:49 -07008485 cmd = find_pairing(conn);
8486
8487 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8488 cmd ? cmd->sk : NULL);
8489
Johan Hedberga511b352014-12-11 21:45:45 +02008490 if (cmd) {
8491 cmd->cmd_complete(cmd, status);
8492 mgmt_pending_remove(cmd);
8493 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008494}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008495
Marcel Holtmann464996a2013-10-15 14:26:24 -07008496void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008497{
8498 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008499 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008500
8501 if (status) {
8502 u8 mgmt_err = mgmt_status(status);
8503 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008504 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008505 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008506 }
8507
Marcel Holtmann464996a2013-10-15 14:26:24 -07008508 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008509 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008510 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008511 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008512
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008513 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008514 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008515
Johan Hedberg47990ea2012-02-22 11:58:37 +02008516 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008517 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008518
8519 if (match.sk)
8520 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008521}
8522
Johan Hedberg890ea892013-03-15 17:06:52 -05008523static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008524{
Johan Hedberg890ea892013-03-15 17:06:52 -05008525 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008526 struct hci_cp_write_eir cp;
8527
Johan Hedberg976eb202012-10-24 21:12:01 +03008528 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008529 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008530
Johan Hedbergc80da272012-02-22 15:38:48 +02008531 memset(hdev->eir, 0, sizeof(hdev->eir));
8532
Johan Hedbergcacaf522012-02-21 00:52:42 +02008533 memset(&cp, 0, sizeof(cp));
8534
Johan Hedberg890ea892013-03-15 17:06:52 -05008535 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008536}
8537
Marcel Holtmann3e248562013-10-15 14:26:25 -07008538void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008539{
8540 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008541 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008542 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008543
8544 if (status) {
8545 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008546
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008547 if (enable && hci_dev_test_and_clear_flag(hdev,
8548 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008549 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008550 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008551 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008552
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008553 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8554 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008555 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008556 }
8557
8558 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008559 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008560 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008561 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008562 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008563 changed = hci_dev_test_and_clear_flag(hdev,
8564 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008565 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008566 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008567 }
8568
8569 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8570
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008571 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008572 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008573
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008574 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008575 sock_put(match.sk);
8576
Johan Hedberg890ea892013-03-15 17:06:52 -05008577 hci_req_init(&req, hdev);
8578
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008579 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8580 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008581 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8582 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008583 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008584 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008585 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008586 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008587
8588 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008589}
8590
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008591static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008592{
8593 struct cmd_lookup *match = data;
8594
Johan Hedberg90e70452012-02-23 23:09:40 +02008595 if (match->sk == NULL) {
8596 match->sk = cmd->sk;
8597 sock_hold(match->sk);
8598 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008599}
8600
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008601void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8602 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008603{
Johan Hedberg90e70452012-02-23 23:09:40 +02008604 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008605
Johan Hedberg92da6092013-03-15 17:06:55 -05008606 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8607 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8608 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008609
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008610 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008611 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8612 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008613 ext_info_changed(hdev, NULL);
8614 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008615
8616 if (match.sk)
8617 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008618}
8619
Marcel Holtmann7667da32013-10-15 14:26:27 -07008620void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008621{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008622 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008623 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008624
Johan Hedberg13928972013-03-15 17:07:00 -05008625 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008626 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008627
8628 memset(&ev, 0, sizeof(ev));
8629 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008630 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008631
Johan Hedberg333ae952015-03-17 13:48:47 +02008632 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008633 if (!cmd) {
8634 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008635
Johan Hedberg13928972013-03-15 17:07:00 -05008636 /* If this is a HCI command related to powering on the
8637 * HCI dev don't send any mgmt signals.
8638 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008639 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008640 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008641 }
8642
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008643 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8644 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008645 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008646}
Szymon Jancc35938b2011-03-22 13:12:21 +01008647
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008648static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8649{
8650 int i;
8651
8652 for (i = 0; i < uuid_count; i++) {
8653 if (!memcmp(uuid, uuids[i], 16))
8654 return true;
8655 }
8656
8657 return false;
8658}
8659
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008660static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8661{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008662 u16 parsed = 0;
8663
8664 while (parsed < eir_len) {
8665 u8 field_len = eir[0];
8666 u8 uuid[16];
8667 int i;
8668
8669 if (field_len == 0)
8670 break;
8671
8672 if (eir_len - parsed < field_len + 1)
8673 break;
8674
8675 switch (eir[1]) {
8676 case EIR_UUID16_ALL:
8677 case EIR_UUID16_SOME:
8678 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008679 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008680 uuid[13] = eir[i + 3];
8681 uuid[12] = eir[i + 2];
8682 if (has_uuid(uuid, uuid_count, uuids))
8683 return true;
8684 }
8685 break;
8686 case EIR_UUID32_ALL:
8687 case EIR_UUID32_SOME:
8688 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008689 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008690 uuid[15] = eir[i + 5];
8691 uuid[14] = eir[i + 4];
8692 uuid[13] = eir[i + 3];
8693 uuid[12] = eir[i + 2];
8694 if (has_uuid(uuid, uuid_count, uuids))
8695 return true;
8696 }
8697 break;
8698 case EIR_UUID128_ALL:
8699 case EIR_UUID128_SOME:
8700 for (i = 0; i + 17 <= field_len; i += 16) {
8701 memcpy(uuid, eir + i + 2, 16);
8702 if (has_uuid(uuid, uuid_count, uuids))
8703 return true;
8704 }
8705 break;
8706 }
8707
8708 parsed += field_len + 1;
8709 eir += field_len + 1;
8710 }
8711
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008712 return false;
8713}
8714
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008715static void restart_le_scan(struct hci_dev *hdev)
8716{
8717 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008718 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008719 return;
8720
8721 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8722 hdev->discovery.scan_start +
8723 hdev->discovery.scan_duration))
8724 return;
8725
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008726 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008727 DISCOV_LE_RESTART_DELAY);
8728}
8729
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008730static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8731 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8732{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008733 /* If a RSSI threshold has been specified, and
8734 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8735 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8736 * is set, let it through for further processing, as we might need to
8737 * restart the scan.
8738 *
8739 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8740 * the results are also dropped.
8741 */
8742 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8743 (rssi == HCI_RSSI_INVALID ||
8744 (rssi < hdev->discovery.rssi &&
8745 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8746 return false;
8747
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008748 if (hdev->discovery.uuid_count != 0) {
8749 /* If a list of UUIDs is provided in filter, results with no
8750 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008751 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008752 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8753 hdev->discovery.uuids) &&
8754 !eir_has_uuids(scan_rsp, scan_rsp_len,
8755 hdev->discovery.uuid_count,
8756 hdev->discovery.uuids))
8757 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008758 }
8759
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008760 /* If duplicate filtering does not report RSSI changes, then restart
8761 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008762 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008763 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8764 restart_le_scan(hdev);
8765
8766 /* Validate RSSI value against the RSSI threshold once more. */
8767 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8768 rssi < hdev->discovery.rssi)
8769 return false;
8770 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008771
8772 return true;
8773}
8774
Marcel Holtmann901801b2013-10-06 23:55:51 -07008775void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008776 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8777 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008778{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008779 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008780 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008781 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008782
Johan Hedberg75ce2082014-07-02 22:42:01 +03008783 /* Don't send events for a non-kernel initiated discovery. With
8784 * LE one exception is if we have pend_le_reports > 0 in which
8785 * case we're doing passive scanning and want these events.
8786 */
8787 if (!hci_discovery_active(hdev)) {
8788 if (link_type == ACL_LINK)
8789 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008790 if (link_type == LE_LINK &&
8791 list_empty(&hdev->pend_le_reports) &&
8792 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03008793 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008794 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03008795 }
Andre Guedes12602d02013-04-30 15:29:40 -03008796
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008797 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008798 /* We are using service discovery */
8799 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8800 scan_rsp_len))
8801 return;
8802 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008803
Johan Hedberg78b781c2016-01-05 13:19:32 +02008804 if (hdev->discovery.limited) {
8805 /* Check for limited discoverable bit */
8806 if (dev_class) {
8807 if (!(dev_class[1] & 0x20))
8808 return;
8809 } else {
8810 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8811 if (!flags || !(flags[0] & LE_AD_LIMITED))
8812 return;
8813 }
8814 }
8815
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008816 /* Make sure that the buffer is big enough. The 5 extra bytes
8817 * are for the potential CoD field.
8818 */
8819 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008820 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008821
Johan Hedberg1dc06092012-01-15 21:01:23 +02008822 memset(buf, 0, sizeof(buf));
8823
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008824 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8825 * RSSI value was reported as 0 when not available. This behavior
8826 * is kept when using device discovery. This is required for full
8827 * backwards compatibility with the API.
8828 *
8829 * However when using service discovery, the value 127 will be
8830 * returned when the RSSI is not available.
8831 */
Szymon Janc91200e92015-01-22 16:57:05 +01008832 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8833 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008834 rssi = 0;
8835
Johan Hedberg841c5642014-07-07 12:45:54 +03008836 bacpy(&ev->addr.bdaddr, bdaddr);
8837 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008838 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008839 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008840
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008841 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008842 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008843 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008844
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008845 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8846 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008847 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008848 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008849
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008850 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008851 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008852 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008853
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008854 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8855 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008856
Marcel Holtmann901801b2013-10-06 23:55:51 -07008857 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008858}
Johan Hedberga88a9652011-03-30 13:18:12 +03008859
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008860void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8861 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008862{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008863 struct mgmt_ev_device_found *ev;
8864 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8865 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008866
Johan Hedbergb644ba32012-01-17 21:48:47 +02008867 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008868
Johan Hedbergb644ba32012-01-17 21:48:47 +02008869 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008870
Johan Hedbergb644ba32012-01-17 21:48:47 +02008871 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008872 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008873 ev->rssi = rssi;
8874
8875 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008876 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008877
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008878 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008879
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008880 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008881}
Johan Hedberg314b2382011-04-27 10:29:57 -04008882
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008883void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008884{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008885 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008886
Marcel Holtmann181d6952020-05-06 09:57:47 +02008887 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008888
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008889 memset(&ev, 0, sizeof(ev));
8890 ev.type = hdev->discovery.type;
8891 ev.discovering = discovering;
8892
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008893 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008894}
Antti Julku5e762442011-08-25 16:48:02 +03008895
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07008896void mgmt_suspending(struct hci_dev *hdev, u8 state)
8897{
8898 struct mgmt_ev_controller_suspend ev;
8899
8900 ev.suspend_state = state;
8901 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
8902}
8903
8904void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
8905 u8 addr_type)
8906{
8907 struct mgmt_ev_controller_resume ev;
8908
8909 ev.wake_reason = reason;
8910 if (bdaddr) {
8911 bacpy(&ev.addr.bdaddr, bdaddr);
8912 ev.addr.type = addr_type;
8913 } else {
8914 memset(&ev.addr, 0, sizeof(ev.addr));
8915 }
8916
8917 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
8918}
8919
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008920static struct hci_mgmt_chan chan = {
8921 .channel = HCI_CHANNEL_CONTROL,
8922 .handler_count = ARRAY_SIZE(mgmt_handlers),
8923 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008924 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008925};
8926
8927int mgmt_init(void)
8928{
8929 return hci_mgmt_chan_register(&chan);
8930}
8931
8932void mgmt_exit(void)
8933{
8934 hci_mgmt_chan_unregister(&chan);
8935}