blob: 8ff9c4bb43d11c975d4c73483f5e989d97b6e0f8 [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 Holtmanne6ed8b72020-12-07 11:02:09 +010043#define MGMT_REVISION 19
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,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800113 MGMT_OP_READ_CONTROLLER_CAP,
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,
Daniel Winkler12410572020-12-03 12:12:49 -0800125 MGMT_OP_ADD_EXT_ADV_PARAMS,
126 MGMT_OP_ADD_EXT_ADV_DATA,
Archie Pusakab4a221e2021-01-22 16:36:11 +0800127 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200128};
129
130static const u16 mgmt_events[] = {
131 MGMT_EV_CONTROLLER_ERROR,
132 MGMT_EV_INDEX_ADDED,
133 MGMT_EV_INDEX_REMOVED,
134 MGMT_EV_NEW_SETTINGS,
135 MGMT_EV_CLASS_OF_DEV_CHANGED,
136 MGMT_EV_LOCAL_NAME_CHANGED,
137 MGMT_EV_NEW_LINK_KEY,
138 MGMT_EV_NEW_LONG_TERM_KEY,
139 MGMT_EV_DEVICE_CONNECTED,
140 MGMT_EV_DEVICE_DISCONNECTED,
141 MGMT_EV_CONNECT_FAILED,
142 MGMT_EV_PIN_CODE_REQUEST,
143 MGMT_EV_USER_CONFIRM_REQUEST,
144 MGMT_EV_USER_PASSKEY_REQUEST,
145 MGMT_EV_AUTH_FAILED,
146 MGMT_EV_DEVICE_FOUND,
147 MGMT_EV_DISCOVERING,
148 MGMT_EV_DEVICE_BLOCKED,
149 MGMT_EV_DEVICE_UNBLOCKED,
150 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300151 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800152 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700153 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200154 MGMT_EV_DEVICE_ADDED,
155 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300156 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200157 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200158 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200159 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700160 MGMT_EV_EXT_INDEX_ADDED,
161 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700162 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700163 MGMT_EV_ADVERTISING_ADDED,
164 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200165 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200166 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200167 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200168 MGMT_EV_DEVICE_FLAGS_CHANGED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700169 MGMT_EV_CONTROLLER_SUSPEND,
170 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200171};
172
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700173static const u16 mgmt_untrusted_commands[] = {
174 MGMT_OP_READ_INDEX_LIST,
175 MGMT_OP_READ_INFO,
176 MGMT_OP_READ_UNCONF_INDEX_LIST,
177 MGMT_OP_READ_CONFIG_INFO,
178 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200179 MGMT_OP_READ_EXT_INFO,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800180 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200181 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000182 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200183 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700184};
185
186static const u16 mgmt_untrusted_events[] = {
187 MGMT_EV_INDEX_ADDED,
188 MGMT_EV_INDEX_REMOVED,
189 MGMT_EV_NEW_SETTINGS,
190 MGMT_EV_CLASS_OF_DEV_CHANGED,
191 MGMT_EV_LOCAL_NAME_CHANGED,
192 MGMT_EV_UNCONF_INDEX_ADDED,
193 MGMT_EV_UNCONF_INDEX_REMOVED,
194 MGMT_EV_NEW_CONFIG_OPTIONS,
195 MGMT_EV_EXT_INDEX_ADDED,
196 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200197 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200198 MGMT_EV_EXP_FEATURE_CHANGED,
Miao-chen Choub52729f2020-06-17 16:39:16 +0200199 MGMT_EV_ADV_MONITOR_ADDED,
Miao-chen Choucdde92e2020-06-17 16:39:17 +0200200 MGMT_EV_ADV_MONITOR_REMOVED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700201};
202
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800203#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200204
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200205#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
206 "\x00\x00\x00\x00\x00\x00\x00\x00"
207
Johan Hedbergca69b792011-11-11 18:10:00 +0200208/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000209static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200210 MGMT_STATUS_SUCCESS,
211 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
212 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
213 MGMT_STATUS_FAILED, /* Hardware Failure */
214 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
215 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200216 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200217 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
218 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
219 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
220 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
221 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
222 MGMT_STATUS_BUSY, /* Command Disallowed */
223 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
224 MGMT_STATUS_REJECTED, /* Rejected Security */
225 MGMT_STATUS_REJECTED, /* Rejected Personal */
226 MGMT_STATUS_TIMEOUT, /* Host Timeout */
227 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
228 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
229 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
230 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
231 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
232 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
233 MGMT_STATUS_BUSY, /* Repeated Attempts */
234 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
235 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
236 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
237 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
238 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
239 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
240 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
241 MGMT_STATUS_FAILED, /* Unspecified Error */
242 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
243 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
244 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
245 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
246 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
247 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
248 MGMT_STATUS_FAILED, /* Unit Link Key Used */
249 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
250 MGMT_STATUS_TIMEOUT, /* Instant Passed */
251 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
252 MGMT_STATUS_FAILED, /* Transaction Collision */
253 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
254 MGMT_STATUS_REJECTED, /* QoS Rejected */
255 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
256 MGMT_STATUS_REJECTED, /* Insufficient Security */
257 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
258 MGMT_STATUS_BUSY, /* Role Switch Pending */
259 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 Hedberg4ae143012013-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 Hedberg4ae143012013-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{
Reo Shiseki353021582020-11-19 16:37:11 +09003393 struct mgmt_rp_get_phy_configuration rp;
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303394
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{
Reo Shiseki353021582020-11-19 16:37:11 +09003457 struct mgmt_cp_set_phy_configuration *cp = data;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303458 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
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003714static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
3715 void *data, u16 data_len)
Marcel Holtmannbc292252020-04-03 21:44:05 +02003716{
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003717 char buf[20];
3718 struct mgmt_rp_read_controller_cap *rp = (void *)buf;
3719 u16 cap_len = 0;
Marcel Holtmannbc292252020-04-03 21:44:05 +02003720 u8 flags = 0;
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003721 u8 tx_power_range[2];
Marcel Holtmannbc292252020-04-03 21:44:05 +02003722
3723 bt_dev_dbg(hdev, "sock %p", sk);
3724
3725 memset(&buf, 0, sizeof(buf));
3726
3727 hci_dev_lock(hdev);
3728
3729 /* When the Read Simple Pairing Options command is supported, then
3730 * the remote public key validation is supported.
3731 */
3732 if (hdev->commands[41] & 0x08)
3733 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3734
3735 flags |= 0x02; /* Remote public key validation (LE) */
3736
3737 /* When the Read Encryption Key Size command is supported, then the
3738 * encryption key size is enforced.
3739 */
3740 if (hdev->commands[20] & 0x10)
3741 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3742
3743 flags |= 0x08; /* Encryption key size enforcement (LE) */
3744
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003745 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS,
3746 &flags, 1);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003747
3748 /* When the Read Simple Pairing Options command is supported, then
3749 * also max encryption key size information is provided.
3750 */
3751 if (hdev->commands[41] & 0x08)
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003752 cap_len = eir_append_le16(rp->cap, cap_len,
3753 MGMT_CAP_MAX_ENC_KEY_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02003754 hdev->max_enc_key_size);
3755
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003756 cap_len = eir_append_le16(rp->cap, cap_len,
3757 MGMT_CAP_SMP_MAX_ENC_KEY_SIZE,
3758 SMP_MAX_ENC_KEY_SIZE);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003759
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003760 /* Append the min/max LE tx power parameters if we were able to fetch
3761 * it from the controller
3762 */
3763 if (hdev->commands[38] & 0x80) {
3764 memcpy(&tx_power_range[0], &hdev->min_le_tx_power, 1);
3765 memcpy(&tx_power_range[1], &hdev->max_le_tx_power, 1);
3766 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR,
3767 tx_power_range, 2);
3768 }
3769
3770 rp->cap_len = cpu_to_le16(cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003771
3772 hci_dev_unlock(hdev);
3773
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003774 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0,
3775 rp, sizeof(*rp) + cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003776}
3777
Marcel Holtmanne625e502020-05-06 09:57:52 +02003778#ifdef CONFIG_BT_FEATURE_DEBUG
3779/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3780static const u8 debug_uuid[16] = {
3781 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3782 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3783};
3784#endif
3785
Alain Michaud15d8ce02020-07-07 17:46:06 +02003786/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3787static const u8 simult_central_periph_uuid[16] = {
3788 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3789 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3790};
3791
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303792/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3793static const u8 rpa_resolution_uuid[16] = {
3794 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3795 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3796};
3797
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003798static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3799 void *data, u16 data_len)
3800{
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303801 char buf[62]; /* Enough space for 3 features */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003802 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3803 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003804 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003805
3806 bt_dev_dbg(hdev, "sock %p", sk);
3807
3808 memset(&buf, 0, sizeof(buf));
3809
Marcel Holtmanne625e502020-05-06 09:57:52 +02003810#ifdef CONFIG_BT_FEATURE_DEBUG
3811 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003812 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003813
3814 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3815 rp->features[idx].flags = cpu_to_le32(flags);
3816 idx++;
3817 }
3818#endif
3819
Alain Michaud15d8ce02020-07-07 17:46:06 +02003820 if (hdev) {
3821 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3822 (hdev->le_states[4] & 0x08) && /* Central */
3823 (hdev->le_states[4] & 0x40) && /* Peripheral */
3824 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3825 flags = BIT(0);
3826 else
3827 flags = 0;
3828
3829 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3830 rp->features[idx].flags = cpu_to_le32(flags);
3831 idx++;
3832 }
3833
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303834 if (hdev && use_ll_privacy(hdev)) {
3835 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3836 flags = BIT(0) | BIT(1);
3837 else
3838 flags = BIT(1);
3839
3840 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3841 rp->features[idx].flags = cpu_to_le32(flags);
3842 idx++;
3843 }
3844
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003845 rp->feature_count = cpu_to_le16(idx);
3846
3847 /* After reading the experimental features information, enable
3848 * the events to update client on any future change.
3849 */
3850 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3851
3852 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3853 MGMT_OP_READ_EXP_FEATURES_INFO,
3854 0, rp, sizeof(*rp) + (20 * idx));
3855}
3856
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303857static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3858 struct sock *skip)
3859{
3860 struct mgmt_ev_exp_feature_changed ev;
3861
3862 memset(&ev, 0, sizeof(ev));
3863 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3864 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3865
3866 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3867 &ev, sizeof(ev),
3868 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3869
3870}
3871
Marcel Holtmanne625e502020-05-06 09:57:52 +02003872#ifdef CONFIG_BT_FEATURE_DEBUG
3873static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3874{
3875 struct mgmt_ev_exp_feature_changed ev;
3876
3877 memset(&ev, 0, sizeof(ev));
3878 memcpy(ev.uuid, debug_uuid, 16);
3879 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3880
3881 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3882 &ev, sizeof(ev),
3883 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3884}
3885#endif
3886
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003887static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3888 void *data, u16 data_len)
3889{
3890 struct mgmt_cp_set_exp_feature *cp = data;
3891 struct mgmt_rp_set_exp_feature rp;
3892
3893 bt_dev_dbg(hdev, "sock %p", sk);
3894
3895 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3896 memset(rp.uuid, 0, 16);
3897 rp.flags = cpu_to_le32(0);
3898
Marcel Holtmanne625e502020-05-06 09:57:52 +02003899#ifdef CONFIG_BT_FEATURE_DEBUG
3900 if (!hdev) {
3901 bool changed = bt_dbg_get();
3902
3903 bt_dbg_set(false);
3904
3905 if (changed)
3906 exp_debug_feature_changed(false, sk);
3907 }
3908#endif
3909
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303910 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3911 bool changed = hci_dev_test_flag(hdev,
3912 HCI_ENABLE_LL_PRIVACY);
3913
3914 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3915
3916 if (changed)
3917 exp_ll_privacy_feature_changed(false, hdev, sk);
3918 }
3919
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003920 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3921
3922 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3923 MGMT_OP_SET_EXP_FEATURE, 0,
3924 &rp, sizeof(rp));
3925 }
3926
Marcel Holtmanne625e502020-05-06 09:57:52 +02003927#ifdef CONFIG_BT_FEATURE_DEBUG
3928 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3929 bool val, changed;
3930 int err;
3931
3932 /* Command requires to use the non-controller index */
3933 if (hdev)
3934 return mgmt_cmd_status(sk, hdev->id,
3935 MGMT_OP_SET_EXP_FEATURE,
3936 MGMT_STATUS_INVALID_INDEX);
3937
3938 /* Parameters are limited to a single octet */
3939 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3940 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3941 MGMT_OP_SET_EXP_FEATURE,
3942 MGMT_STATUS_INVALID_PARAMS);
3943
3944 /* Only boolean on/off is supported */
3945 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3946 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3947 MGMT_OP_SET_EXP_FEATURE,
3948 MGMT_STATUS_INVALID_PARAMS);
3949
3950 val = !!cp->param[0];
3951 changed = val ? !bt_dbg_get() : bt_dbg_get();
3952 bt_dbg_set(val);
3953
3954 memcpy(rp.uuid, debug_uuid, 16);
3955 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3956
3957 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3958
3959 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3960 MGMT_OP_SET_EXP_FEATURE, 0,
3961 &rp, sizeof(rp));
3962
3963 if (changed)
3964 exp_debug_feature_changed(val, sk);
3965
3966 return err;
3967 }
3968#endif
3969
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303970 if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
3971 bool val, changed;
3972 int err;
3973 u32 flags;
3974
3975 /* Command requires to use the controller index */
3976 if (!hdev)
3977 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3978 MGMT_OP_SET_EXP_FEATURE,
3979 MGMT_STATUS_INVALID_INDEX);
3980
3981 /* Changes can only be made when controller is powered down */
3982 if (hdev_is_powered(hdev))
3983 return mgmt_cmd_status(sk, hdev->id,
3984 MGMT_OP_SET_EXP_FEATURE,
3985 MGMT_STATUS_NOT_POWERED);
3986
3987 /* Parameters are limited to a single octet */
3988 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3989 return mgmt_cmd_status(sk, hdev->id,
3990 MGMT_OP_SET_EXP_FEATURE,
3991 MGMT_STATUS_INVALID_PARAMS);
3992
3993 /* Only boolean on/off is supported */
3994 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3995 return mgmt_cmd_status(sk, hdev->id,
3996 MGMT_OP_SET_EXP_FEATURE,
3997 MGMT_STATUS_INVALID_PARAMS);
3998
3999 val = !!cp->param[0];
4000
4001 if (val) {
4002 changed = !hci_dev_test_flag(hdev,
4003 HCI_ENABLE_LL_PRIVACY);
4004 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4005 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
4006
4007 /* Enable LL privacy + supported settings changed */
4008 flags = BIT(0) | BIT(1);
4009 } else {
4010 changed = hci_dev_test_flag(hdev,
4011 HCI_ENABLE_LL_PRIVACY);
4012 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4013
4014 /* Disable LL privacy + supported settings changed */
4015 flags = BIT(1);
4016 }
4017
4018 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4019 rp.flags = cpu_to_le32(flags);
4020
4021 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4022
4023 err = mgmt_cmd_complete(sk, hdev->id,
4024 MGMT_OP_SET_EXP_FEATURE, 0,
4025 &rp, sizeof(rp));
4026
4027 if (changed)
4028 exp_ll_privacy_feature_changed(val, hdev, sk);
4029
4030 return err;
4031 }
4032
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004033 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4034 MGMT_OP_SET_EXP_FEATURE,
4035 MGMT_STATUS_NOT_SUPPORTED);
4036}
4037
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004038#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4039
4040static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4041 u16 data_len)
4042{
4043 struct mgmt_cp_get_device_flags *cp = data;
4044 struct mgmt_rp_get_device_flags rp;
4045 struct bdaddr_list_with_flags *br_params;
4046 struct hci_conn_params *params;
4047 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4048 u32 current_flags = 0;
4049 u8 status = MGMT_STATUS_INVALID_PARAMS;
4050
4051 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4052 &cp->addr.bdaddr, cp->addr.type);
4053
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004054 hci_dev_lock(hdev);
4055
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004056 if (cp->addr.type == BDADDR_BREDR) {
4057 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4058 &cp->addr.bdaddr,
4059 cp->addr.type);
4060 if (!br_params)
4061 goto done;
4062
4063 current_flags = br_params->current_flags;
4064 } else {
4065 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4066 le_addr_type(cp->addr.type));
4067
4068 if (!params)
4069 goto done;
4070
4071 current_flags = params->current_flags;
4072 }
4073
4074 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4075 rp.addr.type = cp->addr.type;
4076 rp.supported_flags = cpu_to_le32(supported_flags);
4077 rp.current_flags = cpu_to_le32(current_flags);
4078
4079 status = MGMT_STATUS_SUCCESS;
4080
4081done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004082 hci_dev_unlock(hdev);
4083
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004084 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4085 &rp, sizeof(rp));
4086}
4087
4088static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4089 bdaddr_t *bdaddr, u8 bdaddr_type,
4090 u32 supported_flags, u32 current_flags)
4091{
4092 struct mgmt_ev_device_flags_changed ev;
4093
4094 bacpy(&ev.addr.bdaddr, bdaddr);
4095 ev.addr.type = bdaddr_type;
4096 ev.supported_flags = cpu_to_le32(supported_flags);
4097 ev.current_flags = cpu_to_le32(current_flags);
4098
4099 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4100}
4101
4102static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4103 u16 len)
4104{
4105 struct mgmt_cp_set_device_flags *cp = data;
4106 struct bdaddr_list_with_flags *br_params;
4107 struct hci_conn_params *params;
4108 u8 status = MGMT_STATUS_INVALID_PARAMS;
4109 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4110 u32 current_flags = __le32_to_cpu(cp->current_flags);
4111
4112 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4113 &cp->addr.bdaddr, cp->addr.type,
4114 __le32_to_cpu(current_flags));
4115
4116 if ((supported_flags | current_flags) != supported_flags) {
4117 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4118 current_flags, supported_flags);
4119 goto done;
4120 }
4121
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004122 hci_dev_lock(hdev);
4123
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004124 if (cp->addr.type == BDADDR_BREDR) {
4125 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4126 &cp->addr.bdaddr,
4127 cp->addr.type);
4128
4129 if (br_params) {
4130 br_params->current_flags = current_flags;
4131 status = MGMT_STATUS_SUCCESS;
4132 } else {
4133 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4134 &cp->addr.bdaddr, cp->addr.type);
4135 }
4136 } else {
4137 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4138 le_addr_type(cp->addr.type));
4139 if (params) {
4140 params->current_flags = current_flags;
4141 status = MGMT_STATUS_SUCCESS;
4142 } else {
4143 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4144 &cp->addr.bdaddr,
4145 le_addr_type(cp->addr.type));
4146 }
4147 }
4148
4149done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004150 hci_dev_unlock(hdev);
4151
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004152 if (status == MGMT_STATUS_SUCCESS)
4153 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4154 supported_flags, current_flags);
4155
4156 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4157 &cp->addr, sizeof(cp->addr));
4158}
4159
Miao-chen Choub52729f2020-06-17 16:39:16 +02004160static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4161 u16 handle)
4162{
4163 struct mgmt_ev_adv_monitor_added ev;
4164
4165 ev.monitor_handle = cpu_to_le16(handle);
4166
4167 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4168}
4169
Archie Pusaka66bd0952021-01-22 16:36:13 +08004170void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004171{
Archie Pusaka66bd0952021-01-22 16:36:13 +08004172 struct mgmt_ev_adv_monitor_removed ev;
4173 struct mgmt_pending_cmd *cmd;
4174 struct sock *sk_skip = NULL;
4175 struct mgmt_cp_remove_adv_monitor *cp;
4176
4177 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4178 if (cmd) {
4179 cp = cmd->param;
4180
4181 if (cp->monitor_handle)
4182 sk_skip = cmd->sk;
4183 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004184
4185 ev.monitor_handle = cpu_to_le16(handle);
4186
Archie Pusaka66bd0952021-01-22 16:36:13 +08004187 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004188}
4189
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004190static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4191 void *data, u16 len)
4192{
4193 struct adv_monitor *monitor = NULL;
4194 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004195 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004196 size_t rp_size = 0;
4197 __u32 supported = 0;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004198 __u32 enabled = 0;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004199 __u16 num_handles = 0;
4200 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4201
4202 BT_DBG("request for %s", hdev->name);
4203
4204 hci_dev_lock(hdev);
4205
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004206 if (msft_monitor_supported(hdev))
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004207 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4208
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004209 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004210 handles[num_handles++] = monitor->handle;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004211
4212 hci_dev_unlock(hdev);
4213
4214 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4215 rp = kmalloc(rp_size, GFP_KERNEL);
4216 if (!rp)
4217 return -ENOMEM;
4218
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004219 /* All supported features are currently enabled */
4220 enabled = supported;
4221
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004222 rp->supported_features = cpu_to_le32(supported);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004223 rp->enabled_features = cpu_to_le32(enabled);
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004224 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4225 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4226 rp->num_handles = cpu_to_le16(num_handles);
4227 if (num_handles)
4228 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4229
Peilin Yecafd4722020-09-09 03:25:51 -04004230 err = mgmt_cmd_complete(sk, hdev->id,
4231 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4232 MGMT_STATUS_SUCCESS, rp, rp_size);
4233
4234 kfree(rp);
4235
4236 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004237}
4238
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004239int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
Miao-chen Choub1395532020-06-17 16:39:14 +02004240{
Miao-chen Choub1395532020-06-17 16:39:14 +02004241 struct mgmt_rp_add_adv_patterns_monitor rp;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004242 struct mgmt_pending_cmd *cmd;
4243 struct adv_monitor *monitor;
4244 int err = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004245
4246 hci_dev_lock(hdev);
4247
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004248 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4249 if (!cmd) {
4250 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4251 if (!cmd)
4252 goto done;
4253 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004254
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004255 monitor = cmd->user_data;
4256 rp.monitor_handle = cpu_to_le16(monitor->handle);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004257
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004258 if (!status) {
4259 mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4260 hdev->adv_monitors_cnt++;
4261 if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4262 monitor->state = ADV_MONITOR_STATE_REGISTERED;
4263 hci_update_background_scan(hdev);
4264 }
4265
4266 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4267 mgmt_status(status), &rp, sizeof(rp));
4268 mgmt_pending_remove(cmd);
4269
4270done:
4271 hci_dev_unlock(hdev);
4272 bt_dev_dbg(hdev, "add monitor %d complete, status %d",
4273 rp.monitor_handle, status);
4274
4275 return err;
4276}
4277
4278static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4279 struct adv_monitor *m, u8 status,
4280 void *data, u16 len, u16 op)
4281{
4282 struct mgmt_rp_add_adv_patterns_monitor rp;
4283 struct mgmt_pending_cmd *cmd;
4284 int err;
4285 bool pending;
4286
4287 hci_dev_lock(hdev);
4288
4289 if (status)
4290 goto unlock;
4291
4292 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4293 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4294 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4295 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4296 status = MGMT_STATUS_BUSY;
Miao-chen Choub1395532020-06-17 16:39:14 +02004297 goto unlock;
4298 }
4299
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004300 cmd = mgmt_pending_add(sk, op, hdev, data, len);
4301 if (!cmd) {
4302 status = MGMT_STATUS_NO_RESOURCES;
4303 goto unlock;
4304 }
4305
4306 pending = hci_add_adv_monitor(hdev, m, &err);
4307 if (err) {
4308 if (err == -ENOSPC || err == -ENOMEM)
4309 status = MGMT_STATUS_NO_RESOURCES;
4310 else if (err == -EINVAL)
4311 status = MGMT_STATUS_INVALID_PARAMS;
4312 else
4313 status = MGMT_STATUS_FAILED;
4314
4315 mgmt_pending_remove(cmd);
4316 goto unlock;
4317 }
4318
4319 if (!pending) {
4320 mgmt_pending_remove(cmd);
4321 rp.monitor_handle = cpu_to_le16(m->handle);
Miao-chen Choub52729f2020-06-17 16:39:16 +02004322 mgmt_adv_monitor_added(sk, hdev, m->handle);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004323 m->state = ADV_MONITOR_STATE_REGISTERED;
4324 hdev->adv_monitors_cnt++;
4325
4326 hci_dev_unlock(hdev);
4327 return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4328 &rp, sizeof(rp));
4329 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004330
Miao-chen Choub1395532020-06-17 16:39:14 +02004331 hci_dev_unlock(hdev);
4332
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004333 cmd->user_data = m;
4334 return 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004335
4336unlock:
Archie Pusaka66bd0952021-01-22 16:36:13 +08004337 hci_free_adv_monitor(hdev, m);
Miao-chen Choub1395532020-06-17 16:39:14 +02004338 hci_dev_unlock(hdev);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004339 return mgmt_cmd_status(sk, hdev->id, op, status);
4340}
4341
4342static void parse_adv_monitor_rssi(struct adv_monitor *m,
4343 struct mgmt_adv_rssi_thresholds *rssi)
4344{
4345 if (rssi) {
4346 m->rssi.low_threshold = rssi->low_threshold;
4347 m->rssi.low_threshold_timeout =
4348 __le16_to_cpu(rssi->low_threshold_timeout);
4349 m->rssi.high_threshold = rssi->high_threshold;
4350 m->rssi.high_threshold_timeout =
4351 __le16_to_cpu(rssi->high_threshold_timeout);
4352 m->rssi.sampling_period = rssi->sampling_period;
4353 } else {
4354 /* Default values. These numbers are the least constricting
4355 * parameters for MSFT API to work, so it behaves as if there
4356 * are no rssi parameter to consider. May need to be changed
4357 * if other API are to be supported.
4358 */
4359 m->rssi.low_threshold = -127;
4360 m->rssi.low_threshold_timeout = 60;
4361 m->rssi.high_threshold = -127;
4362 m->rssi.high_threshold_timeout = 0;
4363 m->rssi.sampling_period = 0;
4364 }
4365}
4366
4367static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
4368 struct mgmt_adv_pattern *patterns)
4369{
4370 u8 offset = 0, length = 0;
4371 struct adv_pattern *p = NULL;
Archie Pusakab4a221e2021-01-22 16:36:11 +08004372 int i;
4373
4374 for (i = 0; i < pattern_count; i++) {
Archie Pusakab4a221e2021-01-22 16:36:11 +08004375 offset = patterns[i].offset;
4376 length = patterns[i].length;
4377 if (offset >= HCI_MAX_AD_LENGTH ||
4378 length > HCI_MAX_AD_LENGTH ||
4379 (offset + length) > HCI_MAX_AD_LENGTH)
4380 return MGMT_STATUS_INVALID_PARAMS;
4381
4382 p = kmalloc(sizeof(*p), GFP_KERNEL);
4383 if (!p)
4384 return MGMT_STATUS_NO_RESOURCES;
4385
4386 p->ad_type = patterns[i].ad_type;
4387 p->offset = patterns[i].offset;
4388 p->length = patterns[i].length;
4389 memcpy(p->value, patterns[i].value, p->length);
4390
4391 INIT_LIST_HEAD(&p->list);
4392 list_add(&p->list, &m->patterns);
4393 }
4394
Archie Pusakab4a221e2021-01-22 16:36:11 +08004395 return MGMT_STATUS_SUCCESS;
4396}
4397
4398static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4399 void *data, u16 len)
4400{
4401 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4402 struct adv_monitor *m = NULL;
4403 u8 status = MGMT_STATUS_SUCCESS;
4404 size_t expected_size = sizeof(*cp);
4405
4406 BT_DBG("request for %s", hdev->name);
4407
4408 if (len <= sizeof(*cp)) {
4409 status = MGMT_STATUS_INVALID_PARAMS;
4410 goto done;
4411 }
4412
4413 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4414 if (len != expected_size) {
4415 status = MGMT_STATUS_INVALID_PARAMS;
4416 goto done;
4417 }
4418
4419 m = kzalloc(sizeof(*m), GFP_KERNEL);
4420 if (!m) {
4421 status = MGMT_STATUS_NO_RESOURCES;
4422 goto done;
4423 }
4424
4425 INIT_LIST_HEAD(&m->patterns);
4426
4427 parse_adv_monitor_rssi(m, NULL);
4428 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4429
4430done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004431 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004432 MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
4433}
4434
4435static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
4436 void *data, u16 len)
4437{
4438 struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = data;
4439 struct adv_monitor *m = NULL;
4440 u8 status = MGMT_STATUS_SUCCESS;
4441 size_t expected_size = sizeof(*cp);
4442
4443 BT_DBG("request for %s", hdev->name);
4444
4445 if (len <= sizeof(*cp)) {
4446 status = MGMT_STATUS_INVALID_PARAMS;
4447 goto done;
4448 }
4449
4450 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4451 if (len != expected_size) {
4452 status = MGMT_STATUS_INVALID_PARAMS;
4453 goto done;
4454 }
4455
4456 m = kzalloc(sizeof(*m), GFP_KERNEL);
4457 if (!m) {
4458 status = MGMT_STATUS_NO_RESOURCES;
4459 goto done;
4460 }
4461
4462 INIT_LIST_HEAD(&m->patterns);
4463
4464 parse_adv_monitor_rssi(m, &cp->rssi);
4465 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4466
4467done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004468 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004469 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
Miao-chen Choub1395532020-06-17 16:39:14 +02004470}
4471
Archie Pusaka66bd0952021-01-22 16:36:13 +08004472int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4473{
4474 struct mgmt_rp_remove_adv_monitor rp;
4475 struct mgmt_cp_remove_adv_monitor *cp;
4476 struct mgmt_pending_cmd *cmd;
4477 int err = 0;
4478
4479 hci_dev_lock(hdev);
4480
4481 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4482 if (!cmd)
4483 goto done;
4484
4485 cp = cmd->param;
4486 rp.monitor_handle = cp->monitor_handle;
4487
4488 if (!status)
4489 hci_update_background_scan(hdev);
4490
4491 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4492 mgmt_status(status), &rp, sizeof(rp));
4493 mgmt_pending_remove(cmd);
4494
4495done:
4496 hci_dev_unlock(hdev);
4497 bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
4498 rp.monitor_handle, status);
4499
4500 return err;
4501}
4502
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004503static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4504 void *data, u16 len)
4505{
4506 struct mgmt_cp_remove_adv_monitor *cp = data;
4507 struct mgmt_rp_remove_adv_monitor rp;
Archie Pusaka66bd0952021-01-22 16:36:13 +08004508 struct mgmt_pending_cmd *cmd;
4509 u16 handle = __le16_to_cpu(cp->monitor_handle);
4510 int err, status;
4511 bool pending;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004512
4513 BT_DBG("request for %s", hdev->name);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004514 rp.monitor_handle = cp->monitor_handle;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004515
4516 hci_dev_lock(hdev);
4517
Archie Pusaka66bd0952021-01-22 16:36:13 +08004518 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4519 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4520 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4521 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4522 status = MGMT_STATUS_BUSY;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004523 goto unlock;
4524 }
4525
Archie Pusaka66bd0952021-01-22 16:36:13 +08004526 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4527 if (!cmd) {
4528 status = MGMT_STATUS_NO_RESOURCES;
4529 goto unlock;
4530 }
4531
4532 if (handle)
4533 pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4534 else
4535 pending = hci_remove_all_adv_monitor(hdev, &err);
4536
4537 if (err) {
4538 mgmt_pending_remove(cmd);
4539
4540 if (err == -ENOENT)
4541 status = MGMT_STATUS_INVALID_INDEX;
4542 else
4543 status = MGMT_STATUS_FAILED;
4544
4545 goto unlock;
4546 }
4547
4548 /* monitor can be removed without forwarding request to controller */
4549 if (!pending) {
4550 mgmt_pending_remove(cmd);
4551 hci_dev_unlock(hdev);
4552
4553 return mgmt_cmd_complete(sk, hdev->id,
4554 MGMT_OP_REMOVE_ADV_MONITOR,
4555 MGMT_STATUS_SUCCESS,
4556 &rp, sizeof(rp));
4557 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004558
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004559 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004560 return 0;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004561
4562unlock:
4563 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4565 status);
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004566}
4567
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004568static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4569 u16 opcode, struct sk_buff *skb)
4570{
4571 struct mgmt_rp_read_local_oob_data mgmt_rp;
4572 size_t rp_size = sizeof(mgmt_rp);
4573 struct mgmt_pending_cmd *cmd;
4574
Marcel Holtmann181d6952020-05-06 09:57:47 +02004575 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004576
4577 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4578 if (!cmd)
4579 return;
4580
4581 if (status || !skb) {
4582 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4583 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4584 goto remove;
4585 }
4586
4587 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4588
4589 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4590 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4591
4592 if (skb->len < sizeof(*rp)) {
4593 mgmt_cmd_status(cmd->sk, hdev->id,
4594 MGMT_OP_READ_LOCAL_OOB_DATA,
4595 MGMT_STATUS_FAILED);
4596 goto remove;
4597 }
4598
4599 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4600 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4601
4602 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4603 } else {
4604 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4605
4606 if (skb->len < sizeof(*rp)) {
4607 mgmt_cmd_status(cmd->sk, hdev->id,
4608 MGMT_OP_READ_LOCAL_OOB_DATA,
4609 MGMT_STATUS_FAILED);
4610 goto remove;
4611 }
4612
4613 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4614 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4615
4616 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4617 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4618 }
4619
4620 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4621 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4622
4623remove:
4624 mgmt_pending_remove(cmd);
4625}
4626
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004627static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004628 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004629{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004630 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004631 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004632 int err;
4633
Marcel Holtmann181d6952020-05-06 09:57:47 +02004634 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004636 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004637
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004638 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004639 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4640 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004641 goto unlock;
4642 }
4643
Andre Guedes9a1a1992012-07-24 15:03:48 -03004644 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004645 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4646 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004647 goto unlock;
4648 }
4649
Johan Hedberg333ae952015-03-17 13:48:47 +02004650 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004651 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4652 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004653 goto unlock;
4654 }
4655
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004656 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004657 if (!cmd) {
4658 err = -ENOMEM;
4659 goto unlock;
4660 }
4661
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004662 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004663
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004664 if (bredr_sc_enabled(hdev))
4665 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4666 else
4667 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4668
4669 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004670 if (err < 0)
4671 mgmt_pending_remove(cmd);
4672
4673unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004674 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004675 return err;
4676}
4677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004678static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004679 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004680{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004681 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004682 int err;
4683
Marcel Holtmann181d6952020-05-06 09:57:47 +02004684 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004685
Johan Hedberg5d57e792015-01-23 10:10:38 +02004686 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004687 return mgmt_cmd_complete(sk, hdev->id,
4688 MGMT_OP_ADD_REMOTE_OOB_DATA,
4689 MGMT_STATUS_INVALID_PARAMS,
4690 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004691
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004692 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004693
Marcel Holtmannec109112014-01-10 02:07:30 -08004694 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4695 struct mgmt_cp_add_remote_oob_data *cp = data;
4696 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004697
Johan Hedbergc19a4952014-11-17 20:52:19 +02004698 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004699 err = mgmt_cmd_complete(sk, hdev->id,
4700 MGMT_OP_ADD_REMOTE_OOB_DATA,
4701 MGMT_STATUS_INVALID_PARAMS,
4702 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004703 goto unlock;
4704 }
4705
Marcel Holtmannec109112014-01-10 02:07:30 -08004706 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004707 cp->addr.type, cp->hash,
4708 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004709 if (err < 0)
4710 status = MGMT_STATUS_FAILED;
4711 else
4712 status = MGMT_STATUS_SUCCESS;
4713
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004714 err = mgmt_cmd_complete(sk, hdev->id,
4715 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4716 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004717 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4718 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004719 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004720 u8 status;
4721
Johan Hedberg86df9202014-10-26 20:52:27 +01004722 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004723 /* Enforce zero-valued 192-bit parameters as
4724 * long as legacy SMP OOB isn't implemented.
4725 */
4726 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4727 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004728 err = mgmt_cmd_complete(sk, hdev->id,
4729 MGMT_OP_ADD_REMOTE_OOB_DATA,
4730 MGMT_STATUS_INVALID_PARAMS,
4731 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004732 goto unlock;
4733 }
4734
Johan Hedberg86df9202014-10-26 20:52:27 +01004735 rand192 = NULL;
4736 hash192 = NULL;
4737 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004738 /* In case one of the P-192 values is set to zero,
4739 * then just disable OOB data for P-192.
4740 */
4741 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4742 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4743 rand192 = NULL;
4744 hash192 = NULL;
4745 } else {
4746 rand192 = cp->rand192;
4747 hash192 = cp->hash192;
4748 }
4749 }
4750
4751 /* In case one of the P-256 values is set to zero, then just
4752 * disable OOB data for P-256.
4753 */
4754 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4755 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4756 rand256 = NULL;
4757 hash256 = NULL;
4758 } else {
4759 rand256 = cp->rand256;
4760 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004761 }
4762
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004763 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004764 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004765 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004766 if (err < 0)
4767 status = MGMT_STATUS_FAILED;
4768 else
4769 status = MGMT_STATUS_SUCCESS;
4770
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004771 err = mgmt_cmd_complete(sk, hdev->id,
4772 MGMT_OP_ADD_REMOTE_OOB_DATA,
4773 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004774 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004775 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4776 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004777 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4778 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004779 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004780
Johan Hedbergc19a4952014-11-17 20:52:19 +02004781unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004782 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004783 return err;
4784}
4785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004786static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004787 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004788{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004789 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004790 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004791 int err;
4792
Marcel Holtmann181d6952020-05-06 09:57:47 +02004793 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004794
Johan Hedbergc19a4952014-11-17 20:52:19 +02004795 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004796 return mgmt_cmd_complete(sk, hdev->id,
4797 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4798 MGMT_STATUS_INVALID_PARAMS,
4799 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004800
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004801 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004802
Johan Hedbergeedbd582014-11-15 09:34:23 +02004803 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4804 hci_remote_oob_data_clear(hdev);
4805 status = MGMT_STATUS_SUCCESS;
4806 goto done;
4807 }
4808
Johan Hedberg6928a922014-10-26 20:46:09 +01004809 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004810 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004811 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004812 else
Szymon Janca6785be2012-12-13 15:11:21 +01004813 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004814
Johan Hedbergeedbd582014-11-15 09:34:23 +02004815done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004816 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4817 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004818
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004819 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004820 return err;
4821}
4822
Johan Hedberge68f0722015-11-11 08:30:30 +02004823void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004824{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004825 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004826
Marcel Holtmann181d6952020-05-06 09:57:47 +02004827 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004828
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004829 hci_dev_lock(hdev);
4830
Johan Hedberg333ae952015-03-17 13:48:47 +02004831 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004832 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004833 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004834
Johan Hedberg78b781c2016-01-05 13:19:32 +02004835 if (!cmd)
4836 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4837
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004838 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004839 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004840 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004841 }
4842
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004843 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004844
4845 /* Handle suspend notifier */
4846 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4847 hdev->suspend_tasks)) {
4848 bt_dev_dbg(hdev, "Unpaused discovery");
4849 wake_up(&hdev->suspend_wait_q);
4850 }
Andre Guedes7c307722013-04-30 15:29:28 -03004851}
4852
Johan Hedberg591752a2015-11-11 08:11:24 +02004853static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4854 uint8_t *mgmt_status)
4855{
4856 switch (type) {
4857 case DISCOV_TYPE_LE:
4858 *mgmt_status = mgmt_le_support(hdev);
4859 if (*mgmt_status)
4860 return false;
4861 break;
4862 case DISCOV_TYPE_INTERLEAVED:
4863 *mgmt_status = mgmt_le_support(hdev);
4864 if (*mgmt_status)
4865 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05004866 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02004867 case DISCOV_TYPE_BREDR:
4868 *mgmt_status = mgmt_bredr_support(hdev);
4869 if (*mgmt_status)
4870 return false;
4871 break;
4872 default:
4873 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4874 return false;
4875 }
4876
4877 return true;
4878}
4879
Johan Hedberg78b781c2016-01-05 13:19:32 +02004880static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4881 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004883 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004884 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004885 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004886 int err;
4887
Marcel Holtmann181d6952020-05-06 09:57:47 +02004888 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004890 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004891
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004892 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004893 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004894 MGMT_STATUS_NOT_POWERED,
4895 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004896 goto failed;
4897 }
4898
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004899 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004900 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004901 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4902 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004903 goto failed;
4904 }
4905
Johan Hedberg591752a2015-11-11 08:11:24 +02004906 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004907 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4908 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004909 goto failed;
4910 }
4911
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004912 /* Can't start discovery when it is paused */
4913 if (hdev->discovery_paused) {
4914 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4915 &cp->type, sizeof(cp->type));
4916 goto failed;
4917 }
4918
Marcel Holtmann22078802014-12-05 11:45:22 +01004919 /* Clear the discovery filter first to free any previously
4920 * allocated memory for the UUID list.
4921 */
4922 hci_discovery_filter_clear(hdev);
4923
Andre Guedes4aab14e2012-02-17 20:39:36 -03004924 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004925 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004926 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4927 hdev->discovery.limited = true;
4928 else
4929 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004930
Johan Hedberg78b781c2016-01-05 13:19:32 +02004931 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004932 if (!cmd) {
4933 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004934 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004935 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004936
Johan Hedberge68f0722015-11-11 08:30:30 +02004937 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004938
4939 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004940 queue_work(hdev->req_workqueue, &hdev->discov_update);
4941 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004942
4943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004944 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004945 return err;
4946}
4947
Johan Hedberg78b781c2016-01-05 13:19:32 +02004948static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4949 void *data, u16 len)
4950{
4951 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4952 data, len);
4953}
4954
4955static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4956 void *data, u16 len)
4957{
4958 return start_discovery_internal(sk, hdev,
4959 MGMT_OP_START_LIMITED_DISCOVERY,
4960 data, len);
4961}
4962
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004963static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4964 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004965{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004966 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4967 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004968}
4969
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004970static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4971 void *data, u16 len)
4972{
4973 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004974 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004975 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4976 u16 uuid_count, expected_len;
4977 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004978 int err;
4979
Marcel Holtmann181d6952020-05-06 09:57:47 +02004980 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004981
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004982 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004983
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004984 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004985 err = mgmt_cmd_complete(sk, hdev->id,
4986 MGMT_OP_START_SERVICE_DISCOVERY,
4987 MGMT_STATUS_NOT_POWERED,
4988 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004989 goto failed;
4990 }
4991
4992 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004993 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004994 err = mgmt_cmd_complete(sk, hdev->id,
4995 MGMT_OP_START_SERVICE_DISCOVERY,
4996 MGMT_STATUS_BUSY, &cp->type,
4997 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004998 goto failed;
4999 }
5000
Abhishek Pandit-Subedi36211f72020-12-17 15:04:08 -08005001 if (hdev->discovery_paused) {
5002 err = mgmt_cmd_complete(sk, hdev->id,
5003 MGMT_OP_START_SERVICE_DISCOVERY,
5004 MGMT_STATUS_BUSY, &cp->type,
5005 sizeof(cp->type));
5006 goto failed;
5007 }
5008
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005009 uuid_count = __le16_to_cpu(cp->uuid_count);
5010 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005011 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
5012 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005013 err = mgmt_cmd_complete(sk, hdev->id,
5014 MGMT_OP_START_SERVICE_DISCOVERY,
5015 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5016 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005017 goto failed;
5018 }
5019
5020 expected_len = sizeof(*cp) + uuid_count * 16;
5021 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005022 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
5023 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005024 err = mgmt_cmd_complete(sk, hdev->id,
5025 MGMT_OP_START_SERVICE_DISCOVERY,
5026 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5027 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005028 goto failed;
5029 }
5030
Johan Hedberg591752a2015-11-11 08:11:24 +02005031 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
5032 err = mgmt_cmd_complete(sk, hdev->id,
5033 MGMT_OP_START_SERVICE_DISCOVERY,
5034 status, &cp->type, sizeof(cp->type));
5035 goto failed;
5036 }
5037
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005038 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02005039 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005040 if (!cmd) {
5041 err = -ENOMEM;
5042 goto failed;
5043 }
5044
Johan Hedberg2922a942014-12-05 13:36:06 +02005045 cmd->cmd_complete = service_discovery_cmd_complete;
5046
Marcel Holtmann22078802014-12-05 11:45:22 +01005047 /* Clear the discovery filter first to free any previously
5048 * allocated memory for the UUID list.
5049 */
5050 hci_discovery_filter_clear(hdev);
5051
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08005052 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005053 hdev->discovery.type = cp->type;
5054 hdev->discovery.rssi = cp->rssi;
5055 hdev->discovery.uuid_count = uuid_count;
5056
5057 if (uuid_count > 0) {
5058 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
5059 GFP_KERNEL);
5060 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005061 err = mgmt_cmd_complete(sk, hdev->id,
5062 MGMT_OP_START_SERVICE_DISCOVERY,
5063 MGMT_STATUS_FAILED,
5064 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005065 mgmt_pending_remove(cmd);
5066 goto failed;
5067 }
5068 }
5069
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005070 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02005071 queue_work(hdev->req_workqueue, &hdev->discov_update);
5072 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005073
5074failed:
5075 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005076 return err;
5077}
5078
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005079void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03005080{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005081 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005082
Marcel Holtmann181d6952020-05-06 09:57:47 +02005083 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005084
5085 hci_dev_lock(hdev);
5086
Johan Hedberg333ae952015-03-17 13:48:47 +02005087 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005088 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005089 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005090 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005091 }
5092
Andre Guedes0e05bba2013-04-30 15:29:33 -03005093 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005094
5095 /* Handle suspend notifier */
5096 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
5097 bt_dev_dbg(hdev, "Paused discovery");
5098 wake_up(&hdev->suspend_wait_q);
5099 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03005100}
5101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005102static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005103 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005104{
Johan Hedbergd9306502012-02-20 23:25:18 +02005105 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005106 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04005107 int err;
5108
Marcel Holtmann181d6952020-05-06 09:57:47 +02005109 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005110
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005111 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005112
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005113 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005114 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5115 MGMT_STATUS_REJECTED, &mgmt_cp->type,
5116 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02005117 goto unlock;
5118 }
5119
5120 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005121 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5122 MGMT_STATUS_INVALID_PARAMS,
5123 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005124 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02005125 }
5126
Johan Hedberg2922a942014-12-05 13:36:06 +02005127 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04005128 if (!cmd) {
5129 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005130 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04005131 }
5132
Johan Hedberg2922a942014-12-05 13:36:06 +02005133 cmd->cmd_complete = generic_cmd_complete;
5134
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005135 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
5136 queue_work(hdev->req_workqueue, &hdev->discov_update);
5137 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04005138
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005139unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005140 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005141 return err;
5142}
5143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005144static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005145 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02005146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005147 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005148 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005149 int err;
5150
Marcel Holtmann181d6952020-05-06 09:57:47 +02005151 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005152
Johan Hedberg561aafb2012-01-04 13:31:59 +02005153 hci_dev_lock(hdev);
5154
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005155 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005156 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5157 MGMT_STATUS_FAILED, &cp->addr,
5158 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005159 goto failed;
5160 }
5161
Johan Hedberga198e7b2012-02-17 14:27:06 +02005162 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005163 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005164 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5165 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
5166 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005167 goto failed;
5168 }
5169
5170 if (cp->name_known) {
5171 e->name_state = NAME_KNOWN;
5172 list_del(&e->list);
5173 } else {
5174 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02005175 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005176 }
5177
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005178 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
5179 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005180
5181failed:
5182 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005183 return err;
5184}
5185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005186static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005187 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005188{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005189 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005190 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005191 int err;
5192
Marcel Holtmann181d6952020-05-06 09:57:47 +02005193 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005194
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005195 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005196 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
5197 MGMT_STATUS_INVALID_PARAMS,
5198 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005200 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005201
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005202 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
5203 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005204 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005205 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005206 goto done;
5207 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005208
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005209 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5210 sk);
5211 status = MGMT_STATUS_SUCCESS;
5212
5213done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005214 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
5215 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005216
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005217 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005218
5219 return err;
5220}
5221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005222static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005223 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005224{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005225 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005226 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005227 int err;
5228
Marcel Holtmann181d6952020-05-06 09:57:47 +02005229 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005230
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005231 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005232 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5233 MGMT_STATUS_INVALID_PARAMS,
5234 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005235
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005236 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005237
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005238 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
5239 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005240 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005241 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005242 goto done;
5243 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005244
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005245 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5246 sk);
5247 status = MGMT_STATUS_SUCCESS;
5248
5249done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005250 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5251 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005253 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005254
5255 return err;
5256}
5257
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005258static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5259 u16 len)
5260{
5261 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05005262 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005263 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005264 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005265
Marcel Holtmann181d6952020-05-06 09:57:47 +02005266 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005267
Szymon Jancc72d4b82012-03-16 16:02:57 +01005268 source = __le16_to_cpu(cp->source);
5269
5270 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005271 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5272 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005273
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005274 hci_dev_lock(hdev);
5275
Szymon Jancc72d4b82012-03-16 16:02:57 +01005276 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005277 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5278 hdev->devid_product = __le16_to_cpu(cp->product);
5279 hdev->devid_version = __le16_to_cpu(cp->version);
5280
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005281 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5282 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005283
Johan Hedberg890ea892013-03-15 17:06:52 -05005284 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02005285 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05005286 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005287
5288 hci_dev_unlock(hdev);
5289
5290 return err;
5291}
5292
Arman Uguray24b4f382015-03-23 15:57:12 -07005293static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5294 u16 opcode)
5295{
Marcel Holtmann181d6952020-05-06 09:57:47 +02005296 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005297}
5298
Marcel Holtmann1904a852015-01-11 13:50:44 -08005299static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5300 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005301{
5302 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005303 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005304 u8 instance;
5305 struct adv_info *adv_instance;
5306 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005307
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305308 hci_dev_lock(hdev);
5309
Johan Hedberg4375f102013-09-25 13:26:10 +03005310 if (status) {
5311 u8 mgmt_err = mgmt_status(status);
5312
5313 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5314 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305315 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005316 }
5317
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005318 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005319 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005320 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005321 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005322
Johan Hedberg4375f102013-09-25 13:26:10 +03005323 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5324 &match);
5325
5326 new_settings(hdev, match.sk);
5327
5328 if (match.sk)
5329 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305330
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005331 /* Handle suspend notifier */
5332 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5333 hdev->suspend_tasks)) {
5334 bt_dev_dbg(hdev, "Paused advertising");
5335 wake_up(&hdev->suspend_wait_q);
5336 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5337 hdev->suspend_tasks)) {
5338 bt_dev_dbg(hdev, "Unpaused advertising");
5339 wake_up(&hdev->suspend_wait_q);
5340 }
5341
Arman Uguray24b4f382015-03-23 15:57:12 -07005342 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005343 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005344 */
5345 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005346 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005347 goto unlock;
5348
Florian Grandel7816b822015-06-18 03:16:45 +02005349 instance = hdev->cur_adv_instance;
5350 if (!instance) {
5351 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5352 struct adv_info, list);
5353 if (!adv_instance)
5354 goto unlock;
5355
5356 instance = adv_instance->instance;
5357 }
5358
Arman Uguray24b4f382015-03-23 15:57:12 -07005359 hci_req_init(&req, hdev);
5360
Johan Hedbergf2252572015-11-18 12:49:20 +02005361 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005362
Florian Grandel7816b822015-06-18 03:16:45 +02005363 if (!err)
5364 err = hci_req_run(&req, enable_advertising_instance);
5365
5366 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005367 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005368
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305369unlock:
5370 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005371}
5372
Marcel Holtmann21b51872013-10-10 09:47:53 -07005373static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5374 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005375{
5376 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005377 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005378 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005379 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005380 int err;
5381
Marcel Holtmann181d6952020-05-06 09:57:47 +02005382 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005383
Johan Hedberge6fe7982013-10-02 15:45:22 +03005384 status = mgmt_le_support(hdev);
5385 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005386 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5387 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005388
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05305389 /* Enabling the experimental LL Privay support disables support for
5390 * advertising.
5391 */
5392 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
5393 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5394 MGMT_STATUS_NOT_SUPPORTED);
5395
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005396 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005397 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5398 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005399
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005400 if (hdev->advertising_paused)
5401 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5402 MGMT_STATUS_BUSY);
5403
Johan Hedberg4375f102013-09-25 13:26:10 +03005404 hci_dev_lock(hdev);
5405
5406 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005407
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005408 /* The following conditions are ones which mean that we should
5409 * not do any HCI communication but directly send a mgmt
5410 * response to user space (after toggling the flag if
5411 * necessary).
5412 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005413 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005414 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5415 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005416 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005417 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005418 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005419 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005420
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005421 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005422 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005423 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005424 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005425 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005426 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005427 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005428 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005429 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005430 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005431 }
5432
5433 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5434 if (err < 0)
5435 goto unlock;
5436
5437 if (changed)
5438 err = new_settings(hdev, sk);
5439
5440 goto unlock;
5441 }
5442
Johan Hedberg333ae952015-03-17 13:48:47 +02005443 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5444 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005445 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5446 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005447 goto unlock;
5448 }
5449
5450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5451 if (!cmd) {
5452 err = -ENOMEM;
5453 goto unlock;
5454 }
5455
5456 hci_req_init(&req, hdev);
5457
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005458 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005459 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005460 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005461 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005462
Florian Grandel7816b822015-06-18 03:16:45 +02005463 cancel_adv_timeout(hdev);
5464
Arman Uguray24b4f382015-03-23 15:57:12 -07005465 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005466 /* Switch to instance "0" for the Set Advertising setting.
5467 * We cannot use update_[adv|scan_rsp]_data() here as the
5468 * HCI_ADVERTISING flag is not yet set.
5469 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005470 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305471
5472 if (ext_adv_capable(hdev)) {
5473 __hci_req_start_ext_adv(&req, 0x00);
5474 } else {
5475 __hci_req_update_adv_data(&req, 0x00);
5476 __hci_req_update_scan_rsp_data(&req, 0x00);
5477 __hci_req_enable_advertising(&req);
5478 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005479 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005480 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005481 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005482
5483 err = hci_req_run(&req, set_advertising_complete);
5484 if (err < 0)
5485 mgmt_pending_remove(cmd);
5486
5487unlock:
5488 hci_dev_unlock(hdev);
5489 return err;
5490}
5491
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005492static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5493 void *data, u16 len)
5494{
5495 struct mgmt_cp_set_static_address *cp = data;
5496 int err;
5497
Marcel Holtmann181d6952020-05-06 09:57:47 +02005498 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005499
Marcel Holtmann62af4442013-10-02 22:10:32 -07005500 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005501 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5502 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005503
5504 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005505 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5506 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005507
5508 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5509 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005510 return mgmt_cmd_status(sk, hdev->id,
5511 MGMT_OP_SET_STATIC_ADDRESS,
5512 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005513
5514 /* Two most significant bits shall be set */
5515 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005516 return mgmt_cmd_status(sk, hdev->id,
5517 MGMT_OP_SET_STATIC_ADDRESS,
5518 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005519 }
5520
5521 hci_dev_lock(hdev);
5522
5523 bacpy(&hdev->static_addr, &cp->bdaddr);
5524
Marcel Holtmann93690c22015-03-06 10:11:21 -08005525 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5526 if (err < 0)
5527 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005528
Marcel Holtmann93690c22015-03-06 10:11:21 -08005529 err = new_settings(hdev, sk);
5530
5531unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005532 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005533 return err;
5534}
5535
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005536static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5537 void *data, u16 len)
5538{
5539 struct mgmt_cp_set_scan_params *cp = data;
5540 __u16 interval, window;
5541 int err;
5542
Marcel Holtmann181d6952020-05-06 09:57:47 +02005543 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005544
5545 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005546 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5547 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005548
5549 interval = __le16_to_cpu(cp->interval);
5550
5551 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005552 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5553 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005554
5555 window = __le16_to_cpu(cp->window);
5556
5557 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005558 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5559 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005560
Marcel Holtmann899e1072013-10-14 09:55:32 -07005561 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005562 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5563 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005564
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005565 hci_dev_lock(hdev);
5566
5567 hdev->le_scan_interval = interval;
5568 hdev->le_scan_window = window;
5569
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005570 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5571 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005572
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005573 /* If background scan is running, restart it so new parameters are
5574 * loaded.
5575 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005576 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005577 hdev->discovery.state == DISCOVERY_STOPPED) {
5578 struct hci_request req;
5579
5580 hci_req_init(&req, hdev);
5581
Sathish Narasimman5c49bcc2020-07-23 18:09:01 +05305582 hci_req_add_le_scan_disable(&req, false);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005583 hci_req_add_le_passive_scan(&req);
5584
5585 hci_req_run(&req, NULL);
5586 }
5587
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005588 hci_dev_unlock(hdev);
5589
5590 return err;
5591}
5592
Marcel Holtmann1904a852015-01-11 13:50:44 -08005593static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5594 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005595{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005596 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005597
Marcel Holtmann181d6952020-05-06 09:57:47 +02005598 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005599
5600 hci_dev_lock(hdev);
5601
Johan Hedberg333ae952015-03-17 13:48:47 +02005602 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005603 if (!cmd)
5604 goto unlock;
5605
5606 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005607 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5608 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005609 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005610 struct mgmt_mode *cp = cmd->param;
5611
5612 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005613 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005614 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005615 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005616
Johan Hedberg33e38b32013-03-15 17:07:05 -05005617 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5618 new_settings(hdev, cmd->sk);
5619 }
5620
5621 mgmt_pending_remove(cmd);
5622
5623unlock:
5624 hci_dev_unlock(hdev);
5625}
5626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005627static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005628 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005629{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005630 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005631 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005632 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005633 int err;
5634
Marcel Holtmann181d6952020-05-06 09:57:47 +02005635 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005636
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005637 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005638 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005639 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5640 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005641
Johan Hedberga7e80f22013-01-09 16:05:19 +02005642 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005643 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5644 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005645
Antti Julkuf6422ec2011-06-22 13:11:56 +03005646 hci_dev_lock(hdev);
5647
Johan Hedberg333ae952015-03-17 13:48:47 +02005648 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005649 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5650 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005651 goto unlock;
5652 }
5653
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005654 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005655 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5656 hdev);
5657 goto unlock;
5658 }
5659
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005660 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005661 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005662 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5663 hdev);
5664 new_settings(hdev, sk);
5665 goto unlock;
5666 }
5667
Johan Hedberg33e38b32013-03-15 17:07:05 -05005668 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5669 data, len);
5670 if (!cmd) {
5671 err = -ENOMEM;
5672 goto unlock;
5673 }
5674
5675 hci_req_init(&req, hdev);
5676
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005677 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005678
5679 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005680 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005681 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5682 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005683 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005684 }
5685
Johan Hedberg33e38b32013-03-15 17:07:05 -05005686unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005687 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005688
Antti Julkuf6422ec2011-06-22 13:11:56 +03005689 return err;
5690}
5691
Marcel Holtmann1904a852015-01-11 13:50:44 -08005692static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005693{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005694 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005695
Marcel Holtmann181d6952020-05-06 09:57:47 +02005696 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005697
5698 hci_dev_lock(hdev);
5699
Johan Hedberg333ae952015-03-17 13:48:47 +02005700 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005701 if (!cmd)
5702 goto unlock;
5703
5704 if (status) {
5705 u8 mgmt_err = mgmt_status(status);
5706
5707 /* We need to restore the flag if related HCI commands
5708 * failed.
5709 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005710 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005711
Johan Hedberga69e8372015-03-06 21:08:53 +02005712 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005713 } else {
5714 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5715 new_settings(hdev, cmd->sk);
5716 }
5717
5718 mgmt_pending_remove(cmd);
5719
5720unlock:
5721 hci_dev_unlock(hdev);
5722}
5723
5724static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5725{
5726 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005727 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005728 struct hci_request req;
5729 int err;
5730
Marcel Holtmann181d6952020-05-06 09:57:47 +02005731 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005732
5733 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5735 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005736
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005737 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5739 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005740
5741 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005742 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5743 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005744
5745 hci_dev_lock(hdev);
5746
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005747 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005748 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5749 goto unlock;
5750 }
5751
5752 if (!hdev_is_powered(hdev)) {
5753 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005754 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5755 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5756 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5757 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5758 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005759 }
5760
Marcel Holtmannce05d602015-03-13 02:11:03 -07005761 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005762
5763 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5764 if (err < 0)
5765 goto unlock;
5766
5767 err = new_settings(hdev, sk);
5768 goto unlock;
5769 }
5770
5771 /* Reject disabling when powered on */
5772 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005773 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5774 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005775 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005776 } else {
5777 /* When configuring a dual-mode controller to operate
5778 * with LE only and using a static address, then switching
5779 * BR/EDR back on is not allowed.
5780 *
5781 * Dual-mode controllers shall operate with the public
5782 * address as its identity address for BR/EDR and LE. So
5783 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005784 *
5785 * The same restrictions applies when secure connections
5786 * has been enabled. For BR/EDR this is a controller feature
5787 * while for LE it is a host stack feature. This means that
5788 * switching BR/EDR back on when secure connections has been
5789 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005790 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005791 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005792 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005793 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005794 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5795 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005796 goto unlock;
5797 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005798 }
5799
Johan Hedberg333ae952015-03-17 13:48:47 +02005800 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005801 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5802 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005803 goto unlock;
5804 }
5805
5806 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5807 if (!cmd) {
5808 err = -ENOMEM;
5809 goto unlock;
5810 }
5811
Johan Hedbergf2252572015-11-18 12:49:20 +02005812 /* We need to flip the bit already here so that
5813 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005814 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005815 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005816
5817 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005818
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005819 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005820 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005821
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005822 /* Since only the advertising data flags will change, there
5823 * is no need to update the scan response data.
5824 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005825 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005826
Johan Hedberg0663ca22013-10-02 13:43:14 +03005827 err = hci_req_run(&req, set_bredr_complete);
5828 if (err < 0)
5829 mgmt_pending_remove(cmd);
5830
5831unlock:
5832 hci_dev_unlock(hdev);
5833 return err;
5834}
5835
Johan Hedberga1443f52015-01-23 15:42:46 +02005836static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5837{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005838 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005839 struct mgmt_mode *cp;
5840
Marcel Holtmann181d6952020-05-06 09:57:47 +02005841 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005842
5843 hci_dev_lock(hdev);
5844
Johan Hedberg333ae952015-03-17 13:48:47 +02005845 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005846 if (!cmd)
5847 goto unlock;
5848
5849 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005850 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5851 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005852 goto remove;
5853 }
5854
5855 cp = cmd->param;
5856
5857 switch (cp->val) {
5858 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005859 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5860 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005861 break;
5862 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005863 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005864 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005865 break;
5866 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005867 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5868 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005869 break;
5870 }
5871
5872 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5873 new_settings(hdev, cmd->sk);
5874
5875remove:
5876 mgmt_pending_remove(cmd);
5877unlock:
5878 hci_dev_unlock(hdev);
5879}
5880
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005881static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5882 void *data, u16 len)
5883{
5884 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005885 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005886 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005887 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005888 int err;
5889
Marcel Holtmann181d6952020-05-06 09:57:47 +02005890 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005891
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005892 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005893 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005894 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5895 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005896
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005897 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005898 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005899 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005900 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5901 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005902
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005903 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005904 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005905 MGMT_STATUS_INVALID_PARAMS);
5906
5907 hci_dev_lock(hdev);
5908
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005909 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005910 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005911 bool changed;
5912
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005913 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005914 changed = !hci_dev_test_and_set_flag(hdev,
5915 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005916 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005917 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005918 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005919 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005920 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005921 changed = hci_dev_test_and_clear_flag(hdev,
5922 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005923 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005924 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005925
5926 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5927 if (err < 0)
5928 goto failed;
5929
5930 if (changed)
5931 err = new_settings(hdev, sk);
5932
5933 goto failed;
5934 }
5935
Johan Hedberg333ae952015-03-17 13:48:47 +02005936 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005937 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5938 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005939 goto failed;
5940 }
5941
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005942 val = !!cp->val;
5943
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005944 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5945 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005946 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5947 goto failed;
5948 }
5949
5950 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5951 if (!cmd) {
5952 err = -ENOMEM;
5953 goto failed;
5954 }
5955
Johan Hedberga1443f52015-01-23 15:42:46 +02005956 hci_req_init(&req, hdev);
5957 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5958 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005959 if (err < 0) {
5960 mgmt_pending_remove(cmd);
5961 goto failed;
5962 }
5963
5964failed:
5965 hci_dev_unlock(hdev);
5966 return err;
5967}
5968
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005969static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5970 void *data, u16 len)
5971{
5972 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005973 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005974 int err;
5975
Marcel Holtmann181d6952020-05-06 09:57:47 +02005976 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005977
Johan Hedbergb97109792014-06-24 14:00:28 +03005978 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005979 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5980 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005981
5982 hci_dev_lock(hdev);
5983
5984 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005985 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005986 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005987 changed = hci_dev_test_and_clear_flag(hdev,
5988 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005989
Johan Hedbergb97109792014-06-24 14:00:28 +03005990 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005991 use_changed = !hci_dev_test_and_set_flag(hdev,
5992 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005993 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005994 use_changed = hci_dev_test_and_clear_flag(hdev,
5995 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005996
5997 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005998 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005999 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
6000 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
6001 sizeof(mode), &mode);
6002 }
6003
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006004 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
6005 if (err < 0)
6006 goto unlock;
6007
6008 if (changed)
6009 err = new_settings(hdev, sk);
6010
6011unlock:
6012 hci_dev_unlock(hdev);
6013 return err;
6014}
6015
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006016static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6017 u16 len)
6018{
6019 struct mgmt_cp_set_privacy *cp = cp_data;
6020 bool changed;
6021 int err;
6022
Marcel Holtmann181d6952020-05-06 09:57:47 +02006023 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006024
6025 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006026 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6027 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006028
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006029 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006030 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6031 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006032
6033 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006034 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6035 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006036
6037 hci_dev_lock(hdev);
6038
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006039 /* If user space supports this command it is also expected to
6040 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
6041 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006042 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006043
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006044 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006045 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006046 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006047 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306048 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006049 if (cp->privacy == 0x02)
6050 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
6051 else
6052 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006053 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006054 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006055 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006056 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306057 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006058 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006059 }
6060
6061 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
6062 if (err < 0)
6063 goto unlock;
6064
6065 if (changed)
6066 err = new_settings(hdev, sk);
6067
6068unlock:
6069 hci_dev_unlock(hdev);
6070 return err;
6071}
6072
Johan Hedberg41edf162014-02-18 10:19:35 +02006073static bool irk_is_valid(struct mgmt_irk_info *irk)
6074{
6075 switch (irk->addr.type) {
6076 case BDADDR_LE_PUBLIC:
6077 return true;
6078
6079 case BDADDR_LE_RANDOM:
6080 /* Two most significant bits shall be set */
6081 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6082 return false;
6083 return true;
6084 }
6085
6086 return false;
6087}
6088
6089static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6090 u16 len)
6091{
6092 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006093 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
6094 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02006095 u16 irk_count, expected_len;
6096 int i, err;
6097
Marcel Holtmann181d6952020-05-06 09:57:47 +02006098 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02006099
6100 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006101 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6102 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02006103
6104 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006105 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006106 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
6107 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006108 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6109 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006110 }
Johan Hedberg41edf162014-02-18 10:19:35 +02006111
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006112 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006113 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006114 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
6115 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006116 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6117 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006118 }
6119
Marcel Holtmann181d6952020-05-06 09:57:47 +02006120 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006121
6122 for (i = 0; i < irk_count; i++) {
6123 struct mgmt_irk_info *key = &cp->irks[i];
6124
6125 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006126 return mgmt_cmd_status(sk, hdev->id,
6127 MGMT_OP_LOAD_IRKS,
6128 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006129 }
6130
6131 hci_dev_lock(hdev);
6132
6133 hci_smp_irks_clear(hdev);
6134
6135 for (i = 0; i < irk_count; i++) {
6136 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02006137
Alain Michaud600a8742020-01-07 00:43:17 +00006138 if (hci_is_blocked_key(hdev,
6139 HCI_BLOCKED_KEY_TYPE_IRK,
6140 irk->val)) {
6141 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
6142 &irk->addr.bdaddr);
6143 continue;
6144 }
6145
Johan Hedberg85813a72015-10-21 18:02:59 +03006146 hci_add_irk(hdev, &irk->addr.bdaddr,
6147 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02006148 BDADDR_ANY);
6149 }
6150
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006151 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02006152
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006153 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02006154
6155 hci_dev_unlock(hdev);
6156
6157 return err;
6158}
6159
Johan Hedberg3f706b72013-01-20 14:27:16 +02006160static bool ltk_is_valid(struct mgmt_ltk_info *key)
6161{
6162 if (key->master != 0x00 && key->master != 0x01)
6163 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08006164
6165 switch (key->addr.type) {
6166 case BDADDR_LE_PUBLIC:
6167 return true;
6168
6169 case BDADDR_LE_RANDOM:
6170 /* Two most significant bits shall be set */
6171 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6172 return false;
6173 return true;
6174 }
6175
6176 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02006177}
6178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006179static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006180 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006181{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006182 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006183 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
6184 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006185 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006186 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006187
Marcel Holtmann181d6952020-05-06 09:57:47 +02006188 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006189
6190 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006191 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6192 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006193
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006194 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006195 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006196 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
6197 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006198 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6199 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006200 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006201
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006202 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006203 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006204 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
6205 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6207 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006208 }
6209
Marcel Holtmann181d6952020-05-06 09:57:47 +02006210 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006211
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006212 for (i = 0; i < key_count; i++) {
6213 struct mgmt_ltk_info *key = &cp->keys[i];
6214
Johan Hedberg3f706b72013-01-20 14:27:16 +02006215 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006216 return mgmt_cmd_status(sk, hdev->id,
6217 MGMT_OP_LOAD_LONG_TERM_KEYS,
6218 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006219 }
6220
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006221 hci_dev_lock(hdev);
6222
6223 hci_smp_ltks_clear(hdev);
6224
6225 for (i = 0; i < key_count; i++) {
6226 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006227 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006228
Alain Michaud600a8742020-01-07 00:43:17 +00006229 if (hci_is_blocked_key(hdev,
6230 HCI_BLOCKED_KEY_TYPE_LTK,
6231 key->val)) {
6232 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6233 &key->addr.bdaddr);
6234 continue;
6235 }
6236
Johan Hedberg61b43352014-05-29 19:36:53 +03006237 switch (key->type) {
6238 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006239 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006240 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006241 break;
6242 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006243 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006244 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006245 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006246 case MGMT_LTK_P256_UNAUTH:
6247 authenticated = 0x00;
6248 type = SMP_LTK_P256;
6249 break;
6250 case MGMT_LTK_P256_AUTH:
6251 authenticated = 0x01;
6252 type = SMP_LTK_P256;
6253 break;
6254 case MGMT_LTK_P256_DEBUG:
6255 authenticated = 0x00;
6256 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006257 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006258 default:
6259 continue;
6260 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006261
Johan Hedberg85813a72015-10-21 18:02:59 +03006262 hci_add_ltk(hdev, &key->addr.bdaddr,
6263 le_addr_type(key->addr.type), type, authenticated,
6264 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006265 }
6266
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006267 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006268 NULL, 0);
6269
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006270 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006271
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006272 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006273}
6274
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006275static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006276{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006277 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006278 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006279 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006280
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006281 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006282
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006283 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006284 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006285 rp.tx_power = conn->tx_power;
6286 rp.max_tx_power = conn->max_tx_power;
6287 } else {
6288 rp.rssi = HCI_RSSI_INVALID;
6289 rp.tx_power = HCI_TX_POWER_INVALID;
6290 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006291 }
6292
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006293 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6294 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006295
6296 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006297 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006298
6299 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006300}
6301
Marcel Holtmann1904a852015-01-11 13:50:44 -08006302static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6303 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006304{
6305 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006306 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006307 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006308 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006309 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006310
Marcel Holtmann181d6952020-05-06 09:57:47 +02006311 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006312
6313 hci_dev_lock(hdev);
6314
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006315 /* Commands sent in request are either Read RSSI or Read Transmit Power
6316 * Level so we check which one was last sent to retrieve connection
6317 * handle. Both commands have handle as first parameter so it's safe to
6318 * cast data on the same command struct.
6319 *
6320 * First command sent is always Read RSSI and we fail only if it fails.
6321 * In other case we simply override error to indicate success as we
6322 * already remembered if TX power value is actually valid.
6323 */
6324 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6325 if (!cp) {
6326 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006327 status = MGMT_STATUS_SUCCESS;
6328 } else {
6329 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006330 }
6331
6332 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006333 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006334 goto unlock;
6335 }
6336
6337 handle = __le16_to_cpu(cp->handle);
6338 conn = hci_conn_hash_lookup_handle(hdev, handle);
6339 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006340 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
6341 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006342 goto unlock;
6343 }
6344
Johan Hedberg333ae952015-03-17 13:48:47 +02006345 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006346 if (!cmd)
6347 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006348
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006349 cmd->cmd_complete(cmd, status);
6350 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006351
6352unlock:
6353 hci_dev_unlock(hdev);
6354}
6355
6356static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6357 u16 len)
6358{
6359 struct mgmt_cp_get_conn_info *cp = data;
6360 struct mgmt_rp_get_conn_info rp;
6361 struct hci_conn *conn;
6362 unsigned long conn_info_age;
6363 int err = 0;
6364
Marcel Holtmann181d6952020-05-06 09:57:47 +02006365 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006366
6367 memset(&rp, 0, sizeof(rp));
6368 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6369 rp.addr.type = cp->addr.type;
6370
6371 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006372 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6373 MGMT_STATUS_INVALID_PARAMS,
6374 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006375
6376 hci_dev_lock(hdev);
6377
6378 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006379 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6380 MGMT_STATUS_NOT_POWERED, &rp,
6381 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006382 goto unlock;
6383 }
6384
6385 if (cp->addr.type == BDADDR_BREDR)
6386 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6387 &cp->addr.bdaddr);
6388 else
6389 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6390
6391 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006392 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6393 MGMT_STATUS_NOT_CONNECTED, &rp,
6394 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006395 goto unlock;
6396 }
6397
Johan Hedberg333ae952015-03-17 13:48:47 +02006398 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006399 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6400 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006401 goto unlock;
6402 }
6403
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006404 /* To avoid client trying to guess when to poll again for information we
6405 * calculate conn info age as random value between min/max set in hdev.
6406 */
6407 conn_info_age = hdev->conn_info_min_age +
6408 prandom_u32_max(hdev->conn_info_max_age -
6409 hdev->conn_info_min_age);
6410
6411 /* Query controller to refresh cached values if they are too old or were
6412 * never read.
6413 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006414 if (time_after(jiffies, conn->conn_info_timestamp +
6415 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006416 !conn->conn_info_timestamp) {
6417 struct hci_request req;
6418 struct hci_cp_read_tx_power req_txp_cp;
6419 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006420 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006421
6422 hci_req_init(&req, hdev);
6423 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6424 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6425 &req_rssi_cp);
6426
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006427 /* For LE links TX power does not change thus we don't need to
6428 * query for it once value is known.
6429 */
6430 if (!bdaddr_type_is_le(cp->addr.type) ||
6431 conn->tx_power == HCI_TX_POWER_INVALID) {
6432 req_txp_cp.handle = cpu_to_le16(conn->handle);
6433 req_txp_cp.type = 0x00;
6434 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6435 sizeof(req_txp_cp), &req_txp_cp);
6436 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006437
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006438 /* Max TX power needs to be read only once per connection */
6439 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6440 req_txp_cp.handle = cpu_to_le16(conn->handle);
6441 req_txp_cp.type = 0x01;
6442 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6443 sizeof(req_txp_cp), &req_txp_cp);
6444 }
6445
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006446 err = hci_req_run(&req, conn_info_refresh_complete);
6447 if (err < 0)
6448 goto unlock;
6449
6450 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6451 data, len);
6452 if (!cmd) {
6453 err = -ENOMEM;
6454 goto unlock;
6455 }
6456
6457 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006458 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006459 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006460
6461 conn->conn_info_timestamp = jiffies;
6462 } else {
6463 /* Cache is valid, just reply with values cached in hci_conn */
6464 rp.rssi = conn->rssi;
6465 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006466 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006467
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6469 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006470 }
6471
6472unlock:
6473 hci_dev_unlock(hdev);
6474 return err;
6475}
6476
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006477static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006478{
6479 struct hci_conn *conn = cmd->user_data;
6480 struct mgmt_rp_get_clock_info rp;
6481 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006482 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006483
6484 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006485 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006486
6487 if (status)
6488 goto complete;
6489
6490 hdev = hci_dev_get(cmd->index);
6491 if (hdev) {
6492 rp.local_clock = cpu_to_le32(hdev->clock);
6493 hci_dev_put(hdev);
6494 }
6495
6496 if (conn) {
6497 rp.piconet_clock = cpu_to_le32(conn->clock);
6498 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6499 }
6500
6501complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006502 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6503 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006504
6505 if (conn) {
6506 hci_conn_drop(conn);
6507 hci_conn_put(conn);
6508 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006509
6510 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006511}
6512
Marcel Holtmann1904a852015-01-11 13:50:44 -08006513static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006514{
Johan Hedberg95868422014-06-28 17:54:07 +03006515 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006516 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006517 struct hci_conn *conn;
6518
Marcel Holtmann181d6952020-05-06 09:57:47 +02006519 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006520
6521 hci_dev_lock(hdev);
6522
6523 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6524 if (!hci_cp)
6525 goto unlock;
6526
6527 if (hci_cp->which) {
6528 u16 handle = __le16_to_cpu(hci_cp->handle);
6529 conn = hci_conn_hash_lookup_handle(hdev, handle);
6530 } else {
6531 conn = NULL;
6532 }
6533
Johan Hedberg333ae952015-03-17 13:48:47 +02006534 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006535 if (!cmd)
6536 goto unlock;
6537
Johan Hedberg69487372014-12-05 13:36:07 +02006538 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006539 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006540
6541unlock:
6542 hci_dev_unlock(hdev);
6543}
6544
6545static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6546 u16 len)
6547{
6548 struct mgmt_cp_get_clock_info *cp = data;
6549 struct mgmt_rp_get_clock_info rp;
6550 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006551 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006552 struct hci_request req;
6553 struct hci_conn *conn;
6554 int err;
6555
Marcel Holtmann181d6952020-05-06 09:57:47 +02006556 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006557
6558 memset(&rp, 0, sizeof(rp));
6559 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6560 rp.addr.type = cp->addr.type;
6561
6562 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006563 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6564 MGMT_STATUS_INVALID_PARAMS,
6565 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006566
6567 hci_dev_lock(hdev);
6568
6569 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006570 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6571 MGMT_STATUS_NOT_POWERED, &rp,
6572 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006573 goto unlock;
6574 }
6575
6576 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6577 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6578 &cp->addr.bdaddr);
6579 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006580 err = mgmt_cmd_complete(sk, hdev->id,
6581 MGMT_OP_GET_CLOCK_INFO,
6582 MGMT_STATUS_NOT_CONNECTED,
6583 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006584 goto unlock;
6585 }
6586 } else {
6587 conn = NULL;
6588 }
6589
6590 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6591 if (!cmd) {
6592 err = -ENOMEM;
6593 goto unlock;
6594 }
6595
Johan Hedberg69487372014-12-05 13:36:07 +02006596 cmd->cmd_complete = clock_info_cmd_complete;
6597
Johan Hedberg95868422014-06-28 17:54:07 +03006598 hci_req_init(&req, hdev);
6599
6600 memset(&hci_cp, 0, sizeof(hci_cp));
6601 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6602
6603 if (conn) {
6604 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006605 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006606
6607 hci_cp.handle = cpu_to_le16(conn->handle);
6608 hci_cp.which = 0x01; /* Piconet clock */
6609 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6610 }
6611
6612 err = hci_req_run(&req, get_clock_info_complete);
6613 if (err < 0)
6614 mgmt_pending_remove(cmd);
6615
6616unlock:
6617 hci_dev_unlock(hdev);
6618 return err;
6619}
6620
Johan Hedberg5a154e62014-12-19 22:26:02 +02006621static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6622{
6623 struct hci_conn *conn;
6624
6625 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6626 if (!conn)
6627 return false;
6628
6629 if (conn->dst_type != type)
6630 return false;
6631
6632 if (conn->state != BT_CONNECTED)
6633 return false;
6634
6635 return true;
6636}
6637
6638/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006639static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006640 u8 addr_type, u8 auto_connect)
6641{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006642 struct hci_conn_params *params;
6643
6644 params = hci_conn_params_add(hdev, addr, addr_type);
6645 if (!params)
6646 return -EIO;
6647
6648 if (params->auto_connect == auto_connect)
6649 return 0;
6650
6651 list_del_init(&params->action);
6652
6653 switch (auto_connect) {
6654 case HCI_AUTO_CONN_DISABLED:
6655 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006656 /* If auto connect is being disabled when we're trying to
6657 * connect to device, keep connecting.
6658 */
6659 if (params->explicit_connect)
6660 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006661 break;
6662 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006663 if (params->explicit_connect)
6664 list_add(&params->action, &hdev->pend_le_conns);
6665 else
6666 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006667 break;
6668 case HCI_AUTO_CONN_DIRECT:
6669 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006670 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006671 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006672 break;
6673 }
6674
6675 params->auto_connect = auto_connect;
6676
Marcel Holtmann181d6952020-05-06 09:57:47 +02006677 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6678 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006679
6680 return 0;
6681}
6682
Marcel Holtmann8afef092014-06-29 22:28:34 +02006683static void device_added(struct sock *sk, struct hci_dev *hdev,
6684 bdaddr_t *bdaddr, u8 type, u8 action)
6685{
6686 struct mgmt_ev_device_added ev;
6687
6688 bacpy(&ev.addr.bdaddr, bdaddr);
6689 ev.addr.type = type;
6690 ev.action = action;
6691
6692 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6693}
6694
Marcel Holtmann2faade52014-06-29 19:44:03 +02006695static int add_device(struct sock *sk, struct hci_dev *hdev,
6696 void *data, u16 len)
6697{
6698 struct mgmt_cp_add_device *cp = data;
6699 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006700 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006701 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006702 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006703
Marcel Holtmann181d6952020-05-06 09:57:47 +02006704 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006705
Johan Hedberg66593582014-07-09 12:59:14 +03006706 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006707 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006708 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6709 MGMT_STATUS_INVALID_PARAMS,
6710 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006711
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006712 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006713 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6714 MGMT_STATUS_INVALID_PARAMS,
6715 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006716
6717 hci_dev_lock(hdev);
6718
Johan Hedberg66593582014-07-09 12:59:14 +03006719 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006720 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006721 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006722 err = mgmt_cmd_complete(sk, hdev->id,
6723 MGMT_OP_ADD_DEVICE,
6724 MGMT_STATUS_INVALID_PARAMS,
6725 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006726 goto unlock;
6727 }
6728
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006729 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6730 &cp->addr.bdaddr,
6731 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006732 if (err)
6733 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006734
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006735 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006736
Johan Hedberg66593582014-07-09 12:59:14 +03006737 goto added;
6738 }
6739
Johan Hedberg85813a72015-10-21 18:02:59 +03006740 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006741
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006742 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006743 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006744 else if (cp->action == 0x01)
6745 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006746 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006747 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006748
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006749 /* Kernel internally uses conn_params with resolvable private
6750 * address, but Add Device allows only identity addresses.
6751 * Make sure it is enforced before calling
6752 * hci_conn_params_lookup.
6753 */
6754 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006755 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6756 MGMT_STATUS_INVALID_PARAMS,
6757 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006758 goto unlock;
6759 }
6760
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006761 /* If the connection parameters don't exist for this device,
6762 * they will be created and configured with defaults.
6763 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006764 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006765 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006766 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6767 MGMT_STATUS_FAILED, &cp->addr,
6768 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006769 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006770 } else {
6771 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6772 addr_type);
6773 if (params)
6774 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006775 }
6776
Johan Hedberg51d7a942015-11-11 08:11:18 +02006777 hci_update_background_scan(hdev);
6778
Johan Hedberg66593582014-07-09 12:59:14 +03006779added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006780 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006781 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6782 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006783
Johan Hedberg51d7a942015-11-11 08:11:18 +02006784 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6785 MGMT_STATUS_SUCCESS, &cp->addr,
6786 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006787
6788unlock:
6789 hci_dev_unlock(hdev);
6790 return err;
6791}
6792
Marcel Holtmann8afef092014-06-29 22:28:34 +02006793static void device_removed(struct sock *sk, struct hci_dev *hdev,
6794 bdaddr_t *bdaddr, u8 type)
6795{
6796 struct mgmt_ev_device_removed ev;
6797
6798 bacpy(&ev.addr.bdaddr, bdaddr);
6799 ev.addr.type = type;
6800
6801 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6802}
6803
Marcel Holtmann2faade52014-06-29 19:44:03 +02006804static int remove_device(struct sock *sk, struct hci_dev *hdev,
6805 void *data, u16 len)
6806{
6807 struct mgmt_cp_remove_device *cp = data;
6808 int err;
6809
Marcel Holtmann181d6952020-05-06 09:57:47 +02006810 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006811
6812 hci_dev_lock(hdev);
6813
6814 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006815 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006816 u8 addr_type;
6817
Johan Hedberg66593582014-07-09 12:59:14 +03006818 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006819 err = mgmt_cmd_complete(sk, hdev->id,
6820 MGMT_OP_REMOVE_DEVICE,
6821 MGMT_STATUS_INVALID_PARAMS,
6822 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006823 goto unlock;
6824 }
6825
Johan Hedberg66593582014-07-09 12:59:14 +03006826 if (cp->addr.type == BDADDR_BREDR) {
6827 err = hci_bdaddr_list_del(&hdev->whitelist,
6828 &cp->addr.bdaddr,
6829 cp->addr.type);
6830 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006831 err = mgmt_cmd_complete(sk, hdev->id,
6832 MGMT_OP_REMOVE_DEVICE,
6833 MGMT_STATUS_INVALID_PARAMS,
6834 &cp->addr,
6835 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006836 goto unlock;
6837 }
6838
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006839 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006840
Johan Hedberg66593582014-07-09 12:59:14 +03006841 device_removed(sk, hdev, &cp->addr.bdaddr,
6842 cp->addr.type);
6843 goto complete;
6844 }
6845
Johan Hedberg85813a72015-10-21 18:02:59 +03006846 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006847
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006848 /* Kernel internally uses conn_params with resolvable private
6849 * address, but Remove Device allows only identity addresses.
6850 * Make sure it is enforced before calling
6851 * hci_conn_params_lookup.
6852 */
6853 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006854 err = mgmt_cmd_complete(sk, hdev->id,
6855 MGMT_OP_REMOVE_DEVICE,
6856 MGMT_STATUS_INVALID_PARAMS,
6857 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006858 goto unlock;
6859 }
6860
Johan Hedbergc71593d2014-07-02 17:37:28 +03006861 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6862 addr_type);
6863 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006864 err = mgmt_cmd_complete(sk, hdev->id,
6865 MGMT_OP_REMOVE_DEVICE,
6866 MGMT_STATUS_INVALID_PARAMS,
6867 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006868 goto unlock;
6869 }
6870
Johan Hedberg679d2b62015-10-16 10:07:52 +03006871 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6872 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006873 err = mgmt_cmd_complete(sk, hdev->id,
6874 MGMT_OP_REMOVE_DEVICE,
6875 MGMT_STATUS_INVALID_PARAMS,
6876 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006877 goto unlock;
6878 }
6879
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006880 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006881 list_del(&params->list);
6882 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006883 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006884
6885 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006886 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006887 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006888 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006889
Marcel Holtmann2faade52014-06-29 19:44:03 +02006890 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006891 err = mgmt_cmd_complete(sk, hdev->id,
6892 MGMT_OP_REMOVE_DEVICE,
6893 MGMT_STATUS_INVALID_PARAMS,
6894 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006895 goto unlock;
6896 }
6897
Johan Hedberg66593582014-07-09 12:59:14 +03006898 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6899 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6900 list_del(&b->list);
6901 kfree(b);
6902 }
6903
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006904 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006905
Johan Hedberg19de0822014-07-06 13:06:51 +03006906 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6907 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6908 continue;
6909 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006910 if (p->explicit_connect) {
6911 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6912 continue;
6913 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006914 list_del(&p->action);
6915 list_del(&p->list);
6916 kfree(p);
6917 }
6918
Marcel Holtmann181d6952020-05-06 09:57:47 +02006919 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006920
Johan Hedberg51d7a942015-11-11 08:11:18 +02006921 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006922 }
6923
Johan Hedberg66593582014-07-09 12:59:14 +03006924complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006925 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6926 MGMT_STATUS_SUCCESS, &cp->addr,
6927 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006928unlock:
6929 hci_dev_unlock(hdev);
6930 return err;
6931}
6932
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006933static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6934 u16 len)
6935{
6936 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006937 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6938 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006939 u16 param_count, expected_len;
6940 int i;
6941
6942 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006943 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6944 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006945
6946 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006947 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006948 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6949 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006950 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6951 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006952 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006953
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006954 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006955 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006956 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6957 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006958 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6959 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006960 }
6961
Marcel Holtmann181d6952020-05-06 09:57:47 +02006962 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006963
6964 hci_dev_lock(hdev);
6965
6966 hci_conn_params_clear_disabled(hdev);
6967
6968 for (i = 0; i < param_count; i++) {
6969 struct mgmt_conn_param *param = &cp->params[i];
6970 struct hci_conn_params *hci_param;
6971 u16 min, max, latency, timeout;
6972 u8 addr_type;
6973
Marcel Holtmann181d6952020-05-06 09:57:47 +02006974 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6975 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006976
6977 if (param->addr.type == BDADDR_LE_PUBLIC) {
6978 addr_type = ADDR_LE_DEV_PUBLIC;
6979 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6980 addr_type = ADDR_LE_DEV_RANDOM;
6981 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006982 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006983 continue;
6984 }
6985
6986 min = le16_to_cpu(param->min_interval);
6987 max = le16_to_cpu(param->max_interval);
6988 latency = le16_to_cpu(param->latency);
6989 timeout = le16_to_cpu(param->timeout);
6990
Marcel Holtmann181d6952020-05-06 09:57:47 +02006991 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6992 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006993
6994 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006995 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006996 continue;
6997 }
6998
6999 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
7000 addr_type);
7001 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007002 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007003 continue;
7004 }
7005
7006 hci_param->conn_min_interval = min;
7007 hci_param->conn_max_interval = max;
7008 hci_param->conn_latency = latency;
7009 hci_param->supervision_timeout = timeout;
7010 }
7011
7012 hci_dev_unlock(hdev);
7013
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007014 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
7015 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007016}
7017
Marcel Holtmanndbece372014-07-04 18:11:55 +02007018static int set_external_config(struct sock *sk, struct hci_dev *hdev,
7019 void *data, u16 len)
7020{
7021 struct mgmt_cp_set_external_config *cp = data;
7022 bool changed;
7023 int err;
7024
Marcel Holtmann181d6952020-05-06 09:57:47 +02007025 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007026
7027 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007028 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7029 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007030
7031 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02007032 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7033 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007034
7035 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02007036 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7037 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007038
7039 hci_dev_lock(hdev);
7040
7041 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07007042 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007043 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007044 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007045
7046 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
7047 if (err < 0)
7048 goto unlock;
7049
7050 if (!changed)
7051 goto unlock;
7052
Marcel Holtmannf4537c02014-07-04 19:06:23 +02007053 err = new_options(hdev, sk);
7054
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007055 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02007056 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007057
Marcel Holtmann516018a2015-03-13 02:11:04 -07007058 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007059 hci_dev_set_flag(hdev, HCI_CONFIG);
7060 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007061
7062 queue_work(hdev->req_workqueue, &hdev->power_on);
7063 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02007064 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007065 mgmt_index_added(hdev);
7066 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02007067 }
7068
7069unlock:
7070 hci_dev_unlock(hdev);
7071 return err;
7072}
7073
Marcel Holtmann9713c172014-07-06 12:11:15 +02007074static int set_public_address(struct sock *sk, struct hci_dev *hdev,
7075 void *data, u16 len)
7076{
7077 struct mgmt_cp_set_public_address *cp = data;
7078 bool changed;
7079 int err;
7080
Marcel Holtmann181d6952020-05-06 09:57:47 +02007081 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007082
7083 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007084 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7085 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007086
7087 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02007088 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7089 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007090
7091 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02007092 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7093 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007094
7095 hci_dev_lock(hdev);
7096
7097 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
7098 bacpy(&hdev->public_addr, &cp->bdaddr);
7099
7100 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
7101 if (err < 0)
7102 goto unlock;
7103
7104 if (!changed)
7105 goto unlock;
7106
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007107 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02007108 err = new_options(hdev, sk);
7109
7110 if (is_configured(hdev)) {
7111 mgmt_index_removed(hdev);
7112
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007113 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007114
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007115 hci_dev_set_flag(hdev, HCI_CONFIG);
7116 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007117
7118 queue_work(hdev->req_workqueue, &hdev->power_on);
7119 }
7120
7121unlock:
7122 hci_dev_unlock(hdev);
7123 return err;
7124}
7125
Johan Hedberg40f66c02015-04-07 21:52:22 +03007126static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
7127 u16 opcode, struct sk_buff *skb)
7128{
7129 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
7130 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
7131 u8 *h192, *r192, *h256, *r256;
7132 struct mgmt_pending_cmd *cmd;
7133 u16 eir_len;
7134 int err;
7135
Marcel Holtmann181d6952020-05-06 09:57:47 +02007136 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007137
7138 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
7139 if (!cmd)
7140 return;
7141
7142 mgmt_cp = cmd->param;
7143
7144 if (status) {
7145 status = mgmt_status(status);
7146 eir_len = 0;
7147
7148 h192 = NULL;
7149 r192 = NULL;
7150 h256 = NULL;
7151 r256 = NULL;
7152 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
7153 struct hci_rp_read_local_oob_data *rp;
7154
7155 if (skb->len != sizeof(*rp)) {
7156 status = MGMT_STATUS_FAILED;
7157 eir_len = 0;
7158 } else {
7159 status = MGMT_STATUS_SUCCESS;
7160 rp = (void *)skb->data;
7161
7162 eir_len = 5 + 18 + 18;
7163 h192 = rp->hash;
7164 r192 = rp->rand;
7165 h256 = NULL;
7166 r256 = NULL;
7167 }
7168 } else {
7169 struct hci_rp_read_local_oob_ext_data *rp;
7170
7171 if (skb->len != sizeof(*rp)) {
7172 status = MGMT_STATUS_FAILED;
7173 eir_len = 0;
7174 } else {
7175 status = MGMT_STATUS_SUCCESS;
7176 rp = (void *)skb->data;
7177
7178 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
7179 eir_len = 5 + 18 + 18;
7180 h192 = NULL;
7181 r192 = NULL;
7182 } else {
7183 eir_len = 5 + 18 + 18 + 18 + 18;
7184 h192 = rp->hash192;
7185 r192 = rp->rand192;
7186 }
7187
7188 h256 = rp->hash256;
7189 r256 = rp->rand256;
7190 }
7191 }
7192
7193 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
7194 if (!mgmt_rp)
7195 goto done;
7196
7197 if (status)
7198 goto send_rsp;
7199
7200 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
7201 hdev->dev_class, 3);
7202
7203 if (h192 && r192) {
7204 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7205 EIR_SSP_HASH_C192, h192, 16);
7206 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7207 EIR_SSP_RAND_R192, r192, 16);
7208 }
7209
7210 if (h256 && r256) {
7211 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7212 EIR_SSP_HASH_C256, h256, 16);
7213 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7214 EIR_SSP_RAND_R256, r256, 16);
7215 }
7216
7217send_rsp:
7218 mgmt_rp->type = mgmt_cp->type;
7219 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7220
7221 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7222 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7223 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7224 if (err < 0 || status)
7225 goto done;
7226
7227 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7228
7229 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7230 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7231 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7232done:
7233 kfree(mgmt_rp);
7234 mgmt_pending_remove(cmd);
7235}
7236
7237static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7238 struct mgmt_cp_read_local_oob_ext_data *cp)
7239{
7240 struct mgmt_pending_cmd *cmd;
7241 struct hci_request req;
7242 int err;
7243
7244 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7245 cp, sizeof(*cp));
7246 if (!cmd)
7247 return -ENOMEM;
7248
7249 hci_req_init(&req, hdev);
7250
7251 if (bredr_sc_enabled(hdev))
7252 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7253 else
7254 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7255
7256 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7257 if (err < 0) {
7258 mgmt_pending_remove(cmd);
7259 return err;
7260 }
7261
7262 return 0;
7263}
7264
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007265static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7266 void *data, u16 data_len)
7267{
7268 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7269 struct mgmt_rp_read_local_oob_ext_data *rp;
7270 size_t rp_len;
7271 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007272 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007273 int err;
7274
Marcel Holtmann181d6952020-05-06 09:57:47 +02007275 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007276
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007277 if (hdev_is_powered(hdev)) {
7278 switch (cp->type) {
7279 case BIT(BDADDR_BREDR):
7280 status = mgmt_bredr_support(hdev);
7281 if (status)
7282 eir_len = 0;
7283 else
7284 eir_len = 5;
7285 break;
7286 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7287 status = mgmt_le_support(hdev);
7288 if (status)
7289 eir_len = 0;
7290 else
7291 eir_len = 9 + 3 + 18 + 18 + 3;
7292 break;
7293 default:
7294 status = MGMT_STATUS_INVALID_PARAMS;
7295 eir_len = 0;
7296 break;
7297 }
7298 } else {
7299 status = MGMT_STATUS_NOT_POWERED;
7300 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007301 }
7302
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007303 rp_len = sizeof(*rp) + eir_len;
7304 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007305 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007306 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007307
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007308 if (status)
7309 goto complete;
7310
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007311 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007312
7313 eir_len = 0;
7314 switch (cp->type) {
7315 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007316 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7317 err = read_local_ssp_oob_req(hdev, sk, cp);
7318 hci_dev_unlock(hdev);
7319 if (!err)
7320 goto done;
7321
7322 status = MGMT_STATUS_FAILED;
7323 goto complete;
7324 } else {
7325 eir_len = eir_append_data(rp->eir, eir_len,
7326 EIR_CLASS_OF_DEV,
7327 hdev->dev_class, 3);
7328 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007329 break;
7330 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007331 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7332 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007333 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007334 status = MGMT_STATUS_FAILED;
7335 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007336 }
7337
Marcel Holtmanne2135682015-04-02 12:00:58 -07007338 /* This should return the active RPA, but since the RPA
7339 * is only programmed on demand, it is really hard to fill
7340 * this in at the moment. For now disallow retrieving
7341 * local out-of-band data when privacy is in use.
7342 *
7343 * Returning the identity address will not help here since
7344 * pairing happens before the identity resolving key is
7345 * known and thus the connection establishment happens
7346 * based on the RPA and not the identity address.
7347 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007348 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007349 hci_dev_unlock(hdev);
7350 status = MGMT_STATUS_REJECTED;
7351 goto complete;
7352 }
7353
7354 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7355 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7356 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7357 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007358 memcpy(addr, &hdev->static_addr, 6);
7359 addr[6] = 0x01;
7360 } else {
7361 memcpy(addr, &hdev->bdaddr, 6);
7362 addr[6] = 0x00;
7363 }
7364
7365 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7366 addr, sizeof(addr));
7367
7368 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7369 role = 0x02;
7370 else
7371 role = 0x01;
7372
7373 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7374 &role, sizeof(role));
7375
Marcel Holtmann5082a592015-03-16 12:39:00 -07007376 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7377 eir_len = eir_append_data(rp->eir, eir_len,
7378 EIR_LE_SC_CONFIRM,
7379 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007380
Marcel Holtmann5082a592015-03-16 12:39:00 -07007381 eir_len = eir_append_data(rp->eir, eir_len,
7382 EIR_LE_SC_RANDOM,
7383 rand, sizeof(rand));
7384 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007385
Johan Hedbergf2252572015-11-18 12:49:20 +02007386 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007387
7388 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7389 flags |= LE_AD_NO_BREDR;
7390
7391 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7392 &flags, sizeof(flags));
7393 break;
7394 }
7395
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007396 hci_dev_unlock(hdev);
7397
Marcel Holtmann72000df2015-03-16 16:11:21 -07007398 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7399
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007400 status = MGMT_STATUS_SUCCESS;
7401
7402complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007403 rp->type = cp->type;
7404 rp->eir_len = cpu_to_le16(eir_len);
7405
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007406 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007407 status, rp, sizeof(*rp) + eir_len);
7408 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007409 goto done;
7410
7411 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7412 rp, sizeof(*rp) + eir_len,
7413 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007414
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007415done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007416 kfree(rp);
7417
7418 return err;
7419}
7420
Arman Uguray089fa8c2015-03-25 18:53:45 -07007421static u32 get_supported_adv_flags(struct hci_dev *hdev)
7422{
7423 u32 flags = 0;
7424
7425 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7426 flags |= MGMT_ADV_FLAG_DISCOV;
7427 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7428 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007429 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007430 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Daniel Winkler12410572020-12-03 12:12:49 -08007431 flags |= MGMT_ADV_PARAM_DURATION;
7432 flags |= MGMT_ADV_PARAM_TIMEOUT;
7433 flags |= MGMT_ADV_PARAM_INTERVALS;
7434 flags |= MGMT_ADV_PARAM_TX_POWER;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007435
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307436 /* In extended adv TX_POWER returned from Set Adv Param
7437 * will be always valid.
7438 */
7439 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7440 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007441 flags |= MGMT_ADV_FLAG_TX_POWER;
7442
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307443 if (ext_adv_capable(hdev)) {
7444 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007445 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7446 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307447
7448 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7449 flags |= MGMT_ADV_FLAG_SEC_2M;
7450
7451 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7452 flags |= MGMT_ADV_FLAG_SEC_CODED;
7453 }
7454
Arman Uguray089fa8c2015-03-25 18:53:45 -07007455 return flags;
7456}
7457
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007458static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7459 void *data, u16 data_len)
7460{
7461 struct mgmt_rp_read_adv_features *rp;
7462 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007463 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007464 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007465 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007466 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007467
Marcel Holtmann181d6952020-05-06 09:57:47 +02007468 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007469
Arman Uguray089fa8c2015-03-25 18:53:45 -07007470 if (!lmp_le_capable(hdev))
7471 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7472 MGMT_STATUS_REJECTED);
7473
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307474 /* Enabling the experimental LL Privay support disables support for
7475 * advertising.
7476 */
7477 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7478 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7479 MGMT_STATUS_NOT_SUPPORTED);
7480
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007481 hci_dev_lock(hdev);
7482
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007483 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007484 rp = kmalloc(rp_len, GFP_ATOMIC);
7485 if (!rp) {
7486 hci_dev_unlock(hdev);
7487 return -ENOMEM;
7488 }
7489
Arman Uguray089fa8c2015-03-25 18:53:45 -07007490 supported_flags = get_supported_adv_flags(hdev);
7491
7492 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007493 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7494 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007495 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007496 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007497
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007498 instance = rp->instance;
7499 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7500 *instance = adv_instance->instance;
7501 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007502 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007503
7504 hci_dev_unlock(hdev);
7505
7506 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7507 MGMT_STATUS_SUCCESS, rp, rp_len);
7508
7509 kfree(rp);
7510
7511 return err;
7512}
7513
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007514static u8 calculate_name_len(struct hci_dev *hdev)
7515{
7516 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7517
7518 return append_local_name(hdev, buf, 0);
7519}
7520
7521static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7522 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007523{
Arman Uguray4117ed72015-03-23 15:57:14 -07007524 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007525
Marcel Holtmann31a32482015-11-19 16:16:42 +01007526 if (is_adv_data) {
7527 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7528 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007529 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007530 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007531
Szymon Janc2bb368702016-09-18 12:50:05 +02007532 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007533 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007534 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007535 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007536 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007537
Szymon Janc2bb368702016-09-18 12:50:05 +02007538 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007539 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007540 }
7541
Szymon Janc2bb368702016-09-18 12:50:05 +02007542 return max_len;
7543}
7544
7545static bool flags_managed(u32 adv_flags)
7546{
7547 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7548 MGMT_ADV_FLAG_LIMITED_DISCOV |
7549 MGMT_ADV_FLAG_MANAGED_FLAGS);
7550}
7551
7552static bool tx_power_managed(u32 adv_flags)
7553{
7554 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7555}
7556
7557static bool name_managed(u32 adv_flags)
7558{
7559 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7560}
7561
7562static bool appearance_managed(u32 adv_flags)
7563{
7564 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7565}
7566
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007567static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7568 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007569{
7570 int i, cur_len;
7571 u8 max_len;
7572
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007573 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007574
Arman Uguray4117ed72015-03-23 15:57:14 -07007575 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007576 return false;
7577
Arman Uguray4117ed72015-03-23 15:57:14 -07007578 /* Make sure that the data is correctly formatted. */
7579 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7580 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007581
Szymon Janc9c9db782016-09-18 12:50:06 +02007582 if (data[i + 1] == EIR_FLAGS &&
7583 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007584 return false;
7585
Szymon Janc2bb368702016-09-18 12:50:05 +02007586 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7587 return false;
7588
7589 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7590 return false;
7591
7592 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7593 return false;
7594
7595 if (data[i + 1] == EIR_APPEARANCE &&
7596 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007597 return false;
7598
Arman Uguray24b4f382015-03-23 15:57:12 -07007599 /* If the current field length would exceed the total data
7600 * length, then it's invalid.
7601 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007602 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007603 return false;
7604 }
7605
7606 return true;
7607}
7608
Daniel Winkler12410572020-12-03 12:12:49 -08007609static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
7610{
7611 u32 supported_flags, phy_flags;
7612
7613 /* The current implementation only supports a subset of the specified
7614 * flags. Also need to check mutual exclusiveness of sec flags.
7615 */
7616 supported_flags = get_supported_adv_flags(hdev);
7617 phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK;
7618 if (adv_flags & ~supported_flags ||
7619 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
7620 return false;
7621
7622 return true;
7623}
7624
7625static bool adv_busy(struct hci_dev *hdev)
7626{
7627 return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7628 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7629 pending_find(MGMT_OP_SET_LE, hdev) ||
7630 pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
7631 pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
7632}
7633
Arman Uguray24b4f382015-03-23 15:57:12 -07007634static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7635 u16 opcode)
7636{
7637 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007638 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007639 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007640 struct adv_info *adv_instance, *n;
7641 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007642
Marcel Holtmann181d6952020-05-06 09:57:47 +02007643 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007644
7645 hci_dev_lock(hdev);
7646
7647 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
Daniel Winkler12410572020-12-03 12:12:49 -08007648 if (!cmd)
7649 cmd = pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev);
Arman Uguray24b4f382015-03-23 15:57:12 -07007650
Florian Grandelfffd38b2015-06-18 03:16:47 +02007651 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7652 if (!adv_instance->pending)
7653 continue;
7654
7655 if (!status) {
7656 adv_instance->pending = false;
7657 continue;
7658 }
7659
7660 instance = adv_instance->instance;
7661
7662 if (hdev->cur_adv_instance == instance)
7663 cancel_adv_timeout(hdev);
7664
7665 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007666 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007667 }
7668
7669 if (!cmd)
7670 goto unlock;
7671
Florian Grandelfffd38b2015-06-18 03:16:47 +02007672 cp = cmd->param;
7673 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007674
7675 if (status)
7676 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7677 mgmt_status(status));
7678 else
7679 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7680 mgmt_status(status), &rp, sizeof(rp));
7681
7682 mgmt_pending_remove(cmd);
7683
7684unlock:
7685 hci_dev_unlock(hdev);
7686}
7687
7688static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7689 void *data, u16 data_len)
7690{
7691 struct mgmt_cp_add_advertising *cp = data;
7692 struct mgmt_rp_add_advertising rp;
7693 u32 flags;
7694 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007695 u16 timeout, duration;
7696 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7697 u8 schedule_instance = 0;
7698 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007699 int err;
7700 struct mgmt_pending_cmd *cmd;
7701 struct hci_request req;
7702
Marcel Holtmann181d6952020-05-06 09:57:47 +02007703 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007704
7705 status = mgmt_le_support(hdev);
7706 if (status)
7707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7708 status);
7709
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307710 /* Enabling the experimental LL Privay support disables support for
7711 * advertising.
7712 */
7713 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7714 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7715 MGMT_STATUS_NOT_SUPPORTED);
7716
Daniel Winkler87597482020-08-25 16:31:50 -07007717 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007718 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7719 MGMT_STATUS_INVALID_PARAMS);
7720
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007721 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7722 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7723 MGMT_STATUS_INVALID_PARAMS);
7724
Arman Uguray24b4f382015-03-23 15:57:12 -07007725 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007726 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007727 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007728
Daniel Winkler12410572020-12-03 12:12:49 -08007729 if (!requested_adv_flags_are_valid(hdev, flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07007730 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7731 MGMT_STATUS_INVALID_PARAMS);
7732
7733 hci_dev_lock(hdev);
7734
Arman Uguray912098a2015-03-23 15:57:15 -07007735 if (timeout && !hdev_is_powered(hdev)) {
7736 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7737 MGMT_STATUS_REJECTED);
7738 goto unlock;
7739 }
7740
Daniel Winkler12410572020-12-03 12:12:49 -08007741 if (adv_busy(hdev)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007742 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7743 MGMT_STATUS_BUSY);
7744 goto unlock;
7745 }
7746
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007747 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7748 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007749 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007750 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7751 MGMT_STATUS_INVALID_PARAMS);
7752 goto unlock;
7753 }
7754
Florian Grandelfffd38b2015-06-18 03:16:47 +02007755 err = hci_add_adv_instance(hdev, cp->instance, flags,
7756 cp->adv_data_len, cp->data,
7757 cp->scan_rsp_len,
7758 cp->data + cp->adv_data_len,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08007759 timeout, duration,
7760 HCI_ADV_TX_POWER_NO_PREFERENCE,
7761 hdev->le_adv_min_interval,
7762 hdev->le_adv_max_interval);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007763 if (err < 0) {
7764 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7765 MGMT_STATUS_FAILED);
7766 goto unlock;
7767 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007768
Florian Grandelfffd38b2015-06-18 03:16:47 +02007769 /* Only trigger an advertising added event if a new instance was
7770 * actually added.
7771 */
7772 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007773 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007774
Florian Grandelfffd38b2015-06-18 03:16:47 +02007775 if (hdev->cur_adv_instance == cp->instance) {
7776 /* If the currently advertised instance is being changed then
7777 * cancel the current advertising and schedule the next
7778 * instance. If there is only one instance then the overridden
7779 * advertising data will be visible right away.
7780 */
7781 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007782
Florian Grandelfffd38b2015-06-18 03:16:47 +02007783 next_instance = hci_get_next_instance(hdev, cp->instance);
7784 if (next_instance)
7785 schedule_instance = next_instance->instance;
7786 } else if (!hdev->adv_instance_timeout) {
7787 /* Immediately advertise the new instance if no other
7788 * instance is currently being advertised.
7789 */
7790 schedule_instance = cp->instance;
7791 }
Arman Uguray912098a2015-03-23 15:57:15 -07007792
Florian Grandelfffd38b2015-06-18 03:16:47 +02007793 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7794 * there is no instance to be advertised then we have no HCI
7795 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007796 */
7797 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007798 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7799 !schedule_instance) {
7800 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007801 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7802 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7803 goto unlock;
7804 }
7805
7806 /* We're good to go, update advertising data, parameters, and start
7807 * advertising.
7808 */
7809 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7810 data_len);
7811 if (!cmd) {
7812 err = -ENOMEM;
7813 goto unlock;
7814 }
7815
7816 hci_req_init(&req, hdev);
7817
Johan Hedbergf2252572015-11-18 12:49:20 +02007818 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007819
Florian Grandelfffd38b2015-06-18 03:16:47 +02007820 if (!err)
7821 err = hci_req_run(&req, add_advertising_complete);
7822
Joseph Hwang72da7b22020-03-10 09:31:50 -07007823 if (err < 0) {
7824 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7825 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007826 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007827 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007828
7829unlock:
7830 hci_dev_unlock(hdev);
7831
7832 return err;
7833}
7834
Daniel Winkler12410572020-12-03 12:12:49 -08007835static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status,
7836 u16 opcode)
7837{
7838 struct mgmt_pending_cmd *cmd;
7839 struct mgmt_cp_add_ext_adv_params *cp;
7840 struct mgmt_rp_add_ext_adv_params rp;
7841 struct adv_info *adv_instance;
7842 u32 flags;
7843
7844 BT_DBG("%s", hdev->name);
7845
7846 hci_dev_lock(hdev);
7847
7848 cmd = pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev);
7849 if (!cmd)
7850 goto unlock;
7851
7852 cp = cmd->param;
7853 adv_instance = hci_find_adv_instance(hdev, cp->instance);
7854 if (!adv_instance)
7855 goto unlock;
7856
7857 rp.instance = cp->instance;
7858 rp.tx_power = adv_instance->tx_power;
7859
7860 /* While we're at it, inform userspace of the available space for this
7861 * advertisement, given the flags that will be used.
7862 */
7863 flags = __le32_to_cpu(cp->flags);
7864 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7865 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
7866
7867 if (status) {
7868 /* If this advertisement was previously advertising and we
7869 * failed to update it, we signal that it has been removed and
7870 * delete its structure
7871 */
7872 if (!adv_instance->pending)
7873 mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
7874
7875 hci_remove_adv_instance(hdev, cp->instance);
7876
7877 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7878 mgmt_status(status));
7879
7880 } else {
7881 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7882 mgmt_status(status), &rp, sizeof(rp));
7883 }
7884
7885unlock:
7886 if (cmd)
7887 mgmt_pending_remove(cmd);
7888
7889 hci_dev_unlock(hdev);
7890}
7891
7892static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
7893 void *data, u16 data_len)
7894{
7895 struct mgmt_cp_add_ext_adv_params *cp = data;
7896 struct mgmt_rp_add_ext_adv_params rp;
7897 struct mgmt_pending_cmd *cmd = NULL;
7898 struct adv_info *adv_instance;
7899 struct hci_request req;
7900 u32 flags, min_interval, max_interval;
7901 u16 timeout, duration;
7902 u8 status;
7903 s8 tx_power;
7904 int err;
7905
7906 BT_DBG("%s", hdev->name);
7907
7908 status = mgmt_le_support(hdev);
7909 if (status)
7910 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7911 status);
7912
7913 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
7914 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7915 MGMT_STATUS_INVALID_PARAMS);
7916
7917 /* The purpose of breaking add_advertising into two separate MGMT calls
7918 * for params and data is to allow more parameters to be added to this
7919 * structure in the future. For this reason, we verify that we have the
7920 * bare minimum structure we know of when the interface was defined. Any
7921 * extra parameters we don't know about will be ignored in this request.
7922 */
7923 if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE)
7924 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7925 MGMT_STATUS_INVALID_PARAMS);
7926
7927 flags = __le32_to_cpu(cp->flags);
7928
7929 if (!requested_adv_flags_are_valid(hdev, flags))
7930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7931 MGMT_STATUS_INVALID_PARAMS);
7932
7933 hci_dev_lock(hdev);
7934
7935 /* In new interface, we require that we are powered to register */
7936 if (!hdev_is_powered(hdev)) {
7937 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7938 MGMT_STATUS_REJECTED);
7939 goto unlock;
7940 }
7941
7942 if (adv_busy(hdev)) {
7943 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7944 MGMT_STATUS_BUSY);
7945 goto unlock;
7946 }
7947
7948 /* Parse defined parameters from request, use defaults otherwise */
7949 timeout = (flags & MGMT_ADV_PARAM_TIMEOUT) ?
7950 __le16_to_cpu(cp->timeout) : 0;
7951
7952 duration = (flags & MGMT_ADV_PARAM_DURATION) ?
7953 __le16_to_cpu(cp->duration) :
7954 hdev->def_multi_adv_rotation_duration;
7955
7956 min_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
7957 __le32_to_cpu(cp->min_interval) :
7958 hdev->le_adv_min_interval;
7959
7960 max_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
7961 __le32_to_cpu(cp->max_interval) :
7962 hdev->le_adv_max_interval;
7963
7964 tx_power = (flags & MGMT_ADV_PARAM_TX_POWER) ?
7965 cp->tx_power :
7966 HCI_ADV_TX_POWER_NO_PREFERENCE;
7967
7968 /* Create advertising instance with no advertising or response data */
7969 err = hci_add_adv_instance(hdev, cp->instance, flags,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08007970 0, NULL, 0, NULL, timeout, duration,
7971 tx_power, min_interval, max_interval);
Daniel Winkler12410572020-12-03 12:12:49 -08007972
7973 if (err < 0) {
7974 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7975 MGMT_STATUS_FAILED);
7976 goto unlock;
7977 }
7978
7979 hdev->cur_adv_instance = cp->instance;
7980 /* Submit request for advertising params if ext adv available */
7981 if (ext_adv_capable(hdev)) {
7982 hci_req_init(&req, hdev);
7983 adv_instance = hci_find_adv_instance(hdev, cp->instance);
7984
7985 /* Updating parameters of an active instance will return a
7986 * Command Disallowed error, so we must first disable the
7987 * instance if it is active.
7988 */
7989 if (!adv_instance->pending)
7990 __hci_req_disable_ext_adv_instance(&req, cp->instance);
7991
7992 __hci_req_setup_ext_adv_instance(&req, cp->instance);
7993
7994 err = hci_req_run(&req, add_ext_adv_params_complete);
7995
7996 if (!err)
7997 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_PARAMS,
7998 hdev, data, data_len);
7999 if (!cmd) {
8000 err = -ENOMEM;
8001 hci_remove_adv_instance(hdev, cp->instance);
8002 goto unlock;
8003 }
8004
8005 } else {
8006 rp.instance = cp->instance;
8007 rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
8008 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8009 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8010 err = mgmt_cmd_complete(sk, hdev->id,
8011 MGMT_OP_ADD_EXT_ADV_PARAMS,
8012 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8013 }
8014
8015unlock:
8016 hci_dev_unlock(hdev);
8017
8018 return err;
8019}
8020
8021static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
8022 u16 data_len)
8023{
8024 struct mgmt_cp_add_ext_adv_data *cp = data;
8025 struct mgmt_rp_add_ext_adv_data rp;
8026 u8 schedule_instance = 0;
8027 struct adv_info *next_instance;
8028 struct adv_info *adv_instance;
8029 int err = 0;
8030 struct mgmt_pending_cmd *cmd;
8031 struct hci_request req;
8032
8033 BT_DBG("%s", hdev->name);
8034
8035 hci_dev_lock(hdev);
8036
8037 adv_instance = hci_find_adv_instance(hdev, cp->instance);
8038
8039 if (!adv_instance) {
8040 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8041 MGMT_STATUS_INVALID_PARAMS);
8042 goto unlock;
8043 }
8044
8045 /* In new interface, we require that we are powered to register */
8046 if (!hdev_is_powered(hdev)) {
8047 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8048 MGMT_STATUS_REJECTED);
8049 goto clear_new_instance;
8050 }
8051
8052 if (adv_busy(hdev)) {
8053 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8054 MGMT_STATUS_BUSY);
8055 goto clear_new_instance;
8056 }
8057
8058 /* Validate new data */
8059 if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data,
8060 cp->adv_data_len, true) ||
8061 !tlv_data_is_valid(hdev, adv_instance->flags, cp->data +
8062 cp->adv_data_len, cp->scan_rsp_len, false)) {
8063 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8064 MGMT_STATUS_INVALID_PARAMS);
8065 goto clear_new_instance;
8066 }
8067
8068 /* Set the data in the advertising instance */
8069 hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len,
8070 cp->data, cp->scan_rsp_len,
8071 cp->data + cp->adv_data_len);
8072
8073 /* We're good to go, update advertising data, parameters, and start
8074 * advertising.
8075 */
8076
8077 hci_req_init(&req, hdev);
8078
8079 hci_req_add(&req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
8080
8081 if (ext_adv_capable(hdev)) {
8082 __hci_req_update_adv_data(&req, cp->instance);
8083 __hci_req_update_scan_rsp_data(&req, cp->instance);
8084 __hci_req_enable_ext_advertising(&req, cp->instance);
8085
8086 } else {
8087 /* If using software rotation, determine next instance to use */
8088
8089 if (hdev->cur_adv_instance == cp->instance) {
8090 /* If the currently advertised instance is being changed
8091 * then cancel the current advertising and schedule the
8092 * next instance. If there is only one instance then the
8093 * overridden advertising data will be visible right
8094 * away
8095 */
8096 cancel_adv_timeout(hdev);
8097
8098 next_instance = hci_get_next_instance(hdev,
8099 cp->instance);
8100 if (next_instance)
8101 schedule_instance = next_instance->instance;
8102 } else if (!hdev->adv_instance_timeout) {
8103 /* Immediately advertise the new instance if no other
8104 * instance is currently being advertised.
8105 */
8106 schedule_instance = cp->instance;
8107 }
8108
8109 /* If the HCI_ADVERTISING flag is set or there is no instance to
8110 * be advertised then we have no HCI communication to make.
8111 * Simply return.
8112 */
8113 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
8114 !schedule_instance) {
8115 if (adv_instance->pending) {
8116 mgmt_advertising_added(sk, hdev, cp->instance);
8117 adv_instance->pending = false;
8118 }
8119 rp.instance = cp->instance;
8120 err = mgmt_cmd_complete(sk, hdev->id,
8121 MGMT_OP_ADD_EXT_ADV_DATA,
8122 MGMT_STATUS_SUCCESS, &rp,
8123 sizeof(rp));
8124 goto unlock;
8125 }
8126
8127 err = __hci_req_schedule_adv_instance(&req, schedule_instance,
8128 true);
8129 }
8130
8131 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
8132 data_len);
8133 if (!cmd) {
8134 err = -ENOMEM;
8135 goto clear_new_instance;
8136 }
8137
8138 if (!err)
8139 err = hci_req_run(&req, add_advertising_complete);
8140
8141 if (err < 0) {
8142 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8143 MGMT_STATUS_FAILED);
8144 mgmt_pending_remove(cmd);
8145 goto clear_new_instance;
8146 }
8147
8148 /* We were successful in updating data, so trigger advertising_added
8149 * event if this is an instance that wasn't previously advertising. If
8150 * a failure occurs in the requests we initiated, we will remove the
8151 * instance again in add_advertising_complete
8152 */
8153 if (adv_instance->pending)
8154 mgmt_advertising_added(sk, hdev, cp->instance);
8155
8156 goto unlock;
8157
8158clear_new_instance:
8159 hci_remove_adv_instance(hdev, cp->instance);
8160
8161unlock:
8162 hci_dev_unlock(hdev);
8163
8164 return err;
8165}
8166
Arman Ugurayda9293352015-03-23 15:57:13 -07008167static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
8168 u16 opcode)
8169{
8170 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02008171 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07008172 struct mgmt_rp_remove_advertising rp;
8173
Marcel Holtmann181d6952020-05-06 09:57:47 +02008174 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07008175
8176 hci_dev_lock(hdev);
8177
8178 /* A failure status here only means that we failed to disable
8179 * advertising. Otherwise, the advertising instance has been removed,
8180 * so report success.
8181 */
8182 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
8183 if (!cmd)
8184 goto unlock;
8185
Florian Grandel01948332015-06-18 03:16:48 +02008186 cp = cmd->param;
8187 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008188
8189 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
8190 &rp, sizeof(rp));
8191 mgmt_pending_remove(cmd);
8192
8193unlock:
8194 hci_dev_unlock(hdev);
8195}
8196
8197static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
8198 void *data, u16 data_len)
8199{
8200 struct mgmt_cp_remove_advertising *cp = data;
8201 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07008202 struct mgmt_pending_cmd *cmd;
8203 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03008204 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008205
Marcel Holtmann181d6952020-05-06 09:57:47 +02008206 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07008207
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05308208 /* Enabling the experimental LL Privay support disables support for
8209 * advertising.
8210 */
8211 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
8212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
8213 MGMT_STATUS_NOT_SUPPORTED);
8214
Arman Ugurayda9293352015-03-23 15:57:13 -07008215 hci_dev_lock(hdev);
8216
Johan Hedberg952497b2015-06-18 21:05:31 +03008217 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02008218 err = mgmt_cmd_status(sk, hdev->id,
8219 MGMT_OP_REMOVE_ADVERTISING,
8220 MGMT_STATUS_INVALID_PARAMS);
8221 goto unlock;
8222 }
8223
Arman Ugurayda9293352015-03-23 15:57:13 -07008224 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
8225 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
8226 pending_find(MGMT_OP_SET_LE, hdev)) {
8227 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8228 MGMT_STATUS_BUSY);
8229 goto unlock;
8230 }
8231
Johan Hedberg17fd08f2015-11-26 12:15:59 +02008232 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07008233 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8234 MGMT_STATUS_INVALID_PARAMS);
8235 goto unlock;
8236 }
8237
Florian Grandel01948332015-06-18 03:16:48 +02008238 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07008239
Daniel Winkler37adf702020-07-14 14:16:00 -07008240 /* If we use extended advertising, instance is disabled and removed */
8241 if (ext_adv_capable(hdev)) {
8242 __hci_req_disable_ext_adv_instance(&req, cp->instance);
8243 __hci_req_remove_ext_adv_instance(&req, cp->instance);
8244 }
8245
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03008246 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07008247
Florian Grandel01948332015-06-18 03:16:48 +02008248 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02008249 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07008250
Florian Grandel01948332015-06-18 03:16:48 +02008251 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
8252 * flag is set or the device isn't powered then we have no HCI
8253 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07008254 */
Florian Grandel01948332015-06-18 03:16:48 +02008255 if (skb_queue_empty(&req.cmd_q) ||
8256 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07008257 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05308258 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02008259 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008260 err = mgmt_cmd_complete(sk, hdev->id,
8261 MGMT_OP_REMOVE_ADVERTISING,
8262 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8263 goto unlock;
8264 }
8265
8266 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
8267 data_len);
8268 if (!cmd) {
8269 err = -ENOMEM;
8270 goto unlock;
8271 }
8272
Arman Ugurayda9293352015-03-23 15:57:13 -07008273 err = hci_req_run(&req, remove_advertising_complete);
8274 if (err < 0)
8275 mgmt_pending_remove(cmd);
8276
8277unlock:
8278 hci_dev_unlock(hdev);
8279
8280 return err;
8281}
8282
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008283static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
8284 void *data, u16 data_len)
8285{
8286 struct mgmt_cp_get_adv_size_info *cp = data;
8287 struct mgmt_rp_get_adv_size_info rp;
8288 u32 flags, supported_flags;
8289 int err;
8290
Marcel Holtmann181d6952020-05-06 09:57:47 +02008291 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008292
8293 if (!lmp_le_capable(hdev))
8294 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8295 MGMT_STATUS_REJECTED);
8296
Daniel Winkler87597482020-08-25 16:31:50 -07008297 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008298 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8299 MGMT_STATUS_INVALID_PARAMS);
8300
8301 flags = __le32_to_cpu(cp->flags);
8302
8303 /* The current implementation only supports a subset of the specified
8304 * flags.
8305 */
8306 supported_flags = get_supported_adv_flags(hdev);
8307 if (flags & ~supported_flags)
8308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8309 MGMT_STATUS_INVALID_PARAMS);
8310
8311 rp.instance = cp->instance;
8312 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008313 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8314 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008315
8316 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8317 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8318
8319 return err;
8320}
8321
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008322static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008323 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008324 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008325 HCI_MGMT_NO_HDEV |
8326 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008327 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008328 HCI_MGMT_NO_HDEV |
8329 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008330 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008331 HCI_MGMT_NO_HDEV |
8332 HCI_MGMT_UNTRUSTED },
8333 { read_controller_info, MGMT_READ_INFO_SIZE,
8334 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008335 { set_powered, MGMT_SETTING_SIZE },
8336 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
8337 { set_connectable, MGMT_SETTING_SIZE },
8338 { set_fast_connectable, MGMT_SETTING_SIZE },
8339 { set_bondable, MGMT_SETTING_SIZE },
8340 { set_link_security, MGMT_SETTING_SIZE },
8341 { set_ssp, MGMT_SETTING_SIZE },
8342 { set_hs, MGMT_SETTING_SIZE },
8343 { set_le, MGMT_SETTING_SIZE },
8344 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
8345 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
8346 { add_uuid, MGMT_ADD_UUID_SIZE },
8347 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008348 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
8349 HCI_MGMT_VAR_LEN },
8350 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
8351 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008352 { disconnect, MGMT_DISCONNECT_SIZE },
8353 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
8354 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
8355 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
8356 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
8357 { pair_device, MGMT_PAIR_DEVICE_SIZE },
8358 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
8359 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
8360 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
8361 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
8362 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
8363 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008364 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
8365 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
8366 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008367 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
8368 { start_discovery, MGMT_START_DISCOVERY_SIZE },
8369 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
8370 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
8371 { block_device, MGMT_BLOCK_DEVICE_SIZE },
8372 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
8373 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
8374 { set_advertising, MGMT_SETTING_SIZE },
8375 { set_bredr, MGMT_SETTING_SIZE },
8376 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
8377 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
8378 { set_secure_conn, MGMT_SETTING_SIZE },
8379 { set_debug_keys, MGMT_SETTING_SIZE },
8380 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008381 { load_irks, MGMT_LOAD_IRKS_SIZE,
8382 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008383 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
8384 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
8385 { add_device, MGMT_ADD_DEVICE_SIZE },
8386 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008387 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
8388 HCI_MGMT_VAR_LEN },
8389 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008390 HCI_MGMT_NO_HDEV |
8391 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008392 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008393 HCI_MGMT_UNCONFIGURED |
8394 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008395 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
8396 HCI_MGMT_UNCONFIGURED },
8397 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
8398 HCI_MGMT_UNCONFIGURED },
8399 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
8400 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07008401 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07008402 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008403 HCI_MGMT_NO_HDEV |
8404 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07008405 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07008406 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
8407 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07008408 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008409 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02008410 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008411 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
8412 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02008413 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05308414 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05308415 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00008416 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
8417 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00008418 { set_wideband_speech, MGMT_SETTING_SIZE },
Daniel Winkler4d9b9522020-12-03 12:12:52 -08008419 { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02008420 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02008421 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
8422 HCI_MGMT_UNTRUSTED |
8423 HCI_MGMT_HDEV_OPTIONAL },
8424 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
8425 HCI_MGMT_VAR_LEN |
8426 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00008427 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
8428 HCI_MGMT_UNTRUSTED },
8429 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
8430 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02008431 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
8432 HCI_MGMT_UNTRUSTED },
8433 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
8434 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02008435 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
8436 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02008437 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02008438 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
8439 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02008440 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Daniel Winkler12410572020-12-03 12:12:49 -08008441 { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE,
8442 HCI_MGMT_VAR_LEN },
8443 { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
8444 HCI_MGMT_VAR_LEN },
Archie Pusakab4a221e2021-01-22 16:36:11 +08008445 { add_adv_patterns_monitor_rssi,
8446 MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
8447 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008448};
8449
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008450void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008451{
Marcel Holtmannced85542015-03-14 19:27:56 -07008452 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03008453
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008454 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8455 return;
8456
Marcel Holtmannf9207332015-03-14 19:27:55 -07008457 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008458 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008459 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8460 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
8461 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008462 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008463 } else {
8464 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
8465 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008466 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008467 }
8468 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008469 case HCI_AMP:
8470 ev.type = 0x02;
8471 break;
8472 default:
8473 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008474 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008475
8476 ev.bus = hdev->bus;
8477
8478 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
8479 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008480}
8481
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008482void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008483{
Marcel Holtmannced85542015-03-14 19:27:56 -07008484 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02008485 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02008486
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008487 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8488 return;
8489
Marcel Holtmannf9207332015-03-14 19:27:55 -07008490 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008491 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008492 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02008493
Marcel Holtmannf9207332015-03-14 19:27:55 -07008494 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8495 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
8496 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008497 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008498 } else {
8499 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
8500 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008501 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008502 }
8503 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008504 case HCI_AMP:
8505 ev.type = 0x02;
8506 break;
8507 default:
8508 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008509 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008510
8511 ev.bus = hdev->bus;
8512
8513 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
8514 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008515}
8516
Andre Guedes6046dc32014-02-26 20:21:51 -03008517/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008518static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03008519{
8520 struct hci_conn_params *p;
8521
8522 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03008523 /* Needed for AUTO_OFF case where might not "really"
8524 * have been powered off.
8525 */
8526 list_del_init(&p->action);
8527
8528 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02008529 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03008530 case HCI_AUTO_CONN_ALWAYS:
8531 list_add(&p->action, &hdev->pend_le_conns);
8532 break;
8533 case HCI_AUTO_CONN_REPORT:
8534 list_add(&p->action, &hdev->pend_le_reports);
8535 break;
8536 default:
8537 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02008538 }
Andre Guedes6046dc32014-02-26 20:21:51 -03008539 }
8540}
8541
Johan Hedberg2ff13892015-11-25 16:15:44 +02008542void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05008543{
8544 struct cmd_lookup match = { NULL, hdev };
8545
Marcel Holtmann181d6952020-05-06 09:57:47 +02008546 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05008547
Johan Hedberg2ff13892015-11-25 16:15:44 +02008548 hci_dev_lock(hdev);
8549
8550 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008551 restart_le_actions(hdev);
8552 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08008553 }
8554
Johan Hedberg229ab392013-03-15 17:06:53 -05008555 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
8556
8557 new_settings(hdev, match.sk);
8558
Johan Hedberg229ab392013-03-15 17:06:53 -05008559 if (match.sk)
8560 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02008561
8562 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05008563}
8564
Johan Hedberg2ff13892015-11-25 16:15:44 +02008565void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02008566{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02008567 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02008568 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02008569
Johan Hedberg229ab392013-03-15 17:06:53 -05008570 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02008571
8572 /* If the power off is because of hdev unregistration let
8573 * use the appropriate INVALID_INDEX status. Otherwise use
8574 * NOT_POWERED. We cover both scenarios here since later in
8575 * mgmt_index_removed() any hci_conn callbacks will have already
8576 * been triggered, potentially causing misleading DISCONNECTED
8577 * status responses.
8578 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008579 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02008580 status = MGMT_STATUS_INVALID_INDEX;
8581 else
8582 status = MGMT_STATUS_NOT_POWERED;
8583
8584 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008585
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008586 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008587 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8588 zero_cod, sizeof(zero_cod),
8589 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008590 ext_info_changed(hdev, NULL);
8591 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008592
Johan Hedberg2ff13892015-11-25 16:15:44 +02008593 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008594
8595 if (match.sk)
8596 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008597}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008598
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008599void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008600{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008601 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008602 u8 status;
8603
Johan Hedberg333ae952015-03-17 13:48:47 +02008604 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008605 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008606 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008607
8608 if (err == -ERFKILL)
8609 status = MGMT_STATUS_RFKILLED;
8610 else
8611 status = MGMT_STATUS_FAILED;
8612
Johan Hedberga69e8372015-03-06 21:08:53 +02008613 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008614
8615 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008616}
8617
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008618void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8619 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008620{
Johan Hedberg86742e12011-11-07 23:13:38 +02008621 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008622
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008623 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008624
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008625 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008626 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008627 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008628 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008629 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008630 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008631
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008632 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008633}
Johan Hedbergf7520542011-01-20 12:34:39 +02008634
Johan Hedbergd7b25452014-05-23 13:19:53 +03008635static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8636{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008637 switch (ltk->type) {
8638 case SMP_LTK:
8639 case SMP_LTK_SLAVE:
8640 if (ltk->authenticated)
8641 return MGMT_LTK_AUTHENTICATED;
8642 return MGMT_LTK_UNAUTHENTICATED;
8643 case SMP_LTK_P256:
8644 if (ltk->authenticated)
8645 return MGMT_LTK_P256_AUTH;
8646 return MGMT_LTK_P256_UNAUTH;
8647 case SMP_LTK_P256_DEBUG:
8648 return MGMT_LTK_P256_DEBUG;
8649 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008650
8651 return MGMT_LTK_UNAUTHENTICATED;
8652}
8653
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008654void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008655{
8656 struct mgmt_ev_new_long_term_key ev;
8657
8658 memset(&ev, 0, sizeof(ev));
8659
Marcel Holtmann5192d302014-02-19 17:11:58 -08008660 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008661 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008662 * to store long term keys. Their addresses will change the
8663 * next time around.
8664 *
8665 * Only when a remote device provides an identity address
8666 * make sure the long term key is stored. If the remote
8667 * identity is known, the long term keys are internally
8668 * mapped to the identity address. So allow static random
8669 * and public addresses here.
8670 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008671 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8672 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8673 ev.store_hint = 0x00;
8674 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008675 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008676
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008677 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008678 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008679 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008680 ev.key.enc_size = key->enc_size;
8681 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008682 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008683
Johan Hedberg2ceba532014-06-16 19:25:16 +03008684 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008685 ev.key.master = 1;
8686
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008687 /* Make sure we copy only the significant bytes based on the
8688 * encryption key size, and set the rest of the value to zeroes.
8689 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008690 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008691 memset(ev.key.val + key->enc_size, 0,
8692 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008693
Marcel Holtmann083368f2013-10-15 14:26:29 -07008694 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008695}
8696
Johan Hedbergcad20c22015-10-12 13:36:19 +02008697void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008698{
8699 struct mgmt_ev_new_irk ev;
8700
8701 memset(&ev, 0, sizeof(ev));
8702
Johan Hedbergcad20c22015-10-12 13:36:19 +02008703 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008704
Johan Hedberg95fbac82014-02-19 15:18:31 +02008705 bacpy(&ev.rpa, &irk->rpa);
8706 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8707 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8708 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8709
8710 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8711}
8712
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008713void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8714 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008715{
8716 struct mgmt_ev_new_csrk ev;
8717
8718 memset(&ev, 0, sizeof(ev));
8719
8720 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008721 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008722 * to store signature resolving keys. Their addresses will change
8723 * the next time around.
8724 *
8725 * Only when a remote device provides an identity address
8726 * make sure the signature resolving key is stored. So allow
8727 * static random and public addresses here.
8728 */
8729 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8730 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8731 ev.store_hint = 0x00;
8732 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008733 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008734
8735 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8736 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008737 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008738 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8739
8740 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8741}
8742
Andre Guedesffb5a8272014-07-01 18:10:11 -03008743void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008744 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8745 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008746{
8747 struct mgmt_ev_new_conn_param ev;
8748
Johan Hedbergc103aea2014-07-02 17:37:34 +03008749 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8750 return;
8751
Andre Guedesffb5a8272014-07-01 18:10:11 -03008752 memset(&ev, 0, sizeof(ev));
8753 bacpy(&ev.addr.bdaddr, bdaddr);
8754 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008755 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008756 ev.min_interval = cpu_to_le16(min_interval);
8757 ev.max_interval = cpu_to_le16(max_interval);
8758 ev.latency = cpu_to_le16(latency);
8759 ev.timeout = cpu_to_le16(timeout);
8760
8761 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8762}
8763
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008764void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
8765 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008766{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008767 char buf[512];
8768 struct mgmt_ev_device_connected *ev = (void *) buf;
8769 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008770
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008771 bacpy(&ev->addr.bdaddr, &conn->dst);
8772 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008773
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008774 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008775
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008776 /* We must ensure that the EIR Data fields are ordered and
8777 * unique. Keep it simple for now and avoid the problem by not
8778 * adding any BR/EDR data to the LE adv.
8779 */
8780 if (conn->le_adv_data_len > 0) {
8781 memcpy(&ev->eir[eir_len],
8782 conn->le_adv_data, conn->le_adv_data_len);
8783 eir_len = conn->le_adv_data_len;
8784 } else {
8785 if (name_len > 0)
8786 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8787 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008788
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008789 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008790 eir_len = eir_append_data(ev->eir, eir_len,
8791 EIR_CLASS_OF_DEV,
8792 conn->dev_class, 3);
8793 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008794
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008795 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008796
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008797 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8798 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008799}
8800
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008801static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008802{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008803 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008804
Johan Hedbergf5818c22014-12-05 13:36:02 +02008805 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008806
8807 *sk = cmd->sk;
8808 sock_hold(*sk);
8809
Johan Hedberga664b5b2011-02-19 12:06:02 -03008810 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008811}
8812
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008813static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008814{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008815 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008816 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008817
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008818 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8819
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008820 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008821 mgmt_pending_remove(cmd);
8822}
8823
Johan Hedberg84c61d92014-08-01 11:13:30 +03008824bool mgmt_powering_down(struct hci_dev *hdev)
8825{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008826 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008827 struct mgmt_mode *cp;
8828
Johan Hedberg333ae952015-03-17 13:48:47 +02008829 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008830 if (!cmd)
8831 return false;
8832
8833 cp = cmd->param;
8834 if (!cp->val)
8835 return true;
8836
8837 return false;
8838}
8839
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008840void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008841 u8 link_type, u8 addr_type, u8 reason,
8842 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008843{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008844 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008845 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008846
Johan Hedberg84c61d92014-08-01 11:13:30 +03008847 /* The connection is still in hci_conn_hash so test for 1
8848 * instead of 0 to know if this is the last one.
8849 */
8850 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8851 cancel_delayed_work(&hdev->power_off);
8852 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008853 }
8854
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008855 if (!mgmt_connected)
8856 return;
8857
Andre Guedes57eb7762013-10-30 19:01:41 -03008858 if (link_type != ACL_LINK && link_type != LE_LINK)
8859 return;
8860
Johan Hedberg744cf192011-11-08 20:40:14 +02008861 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008862
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008863 bacpy(&ev.addr.bdaddr, bdaddr);
8864 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8865 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008866
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07008867 /* Report disconnects due to suspend */
8868 if (hdev->suspended)
8869 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
8870
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008871 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008872
8873 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008874 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008875
Johan Hedberg124f6e32012-02-09 13:50:12 +02008876 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008877 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008878}
8879
Marcel Holtmann78929242013-10-06 23:55:47 -07008880void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8881 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008882{
Andre Guedes3655bba2013-10-30 19:01:40 -03008883 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8884 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008885 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008886
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008887 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8888 hdev);
8889
Johan Hedberg333ae952015-03-17 13:48:47 +02008890 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008891 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008892 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008893
Andre Guedes3655bba2013-10-30 19:01:40 -03008894 cp = cmd->param;
8895
8896 if (bacmp(bdaddr, &cp->addr.bdaddr))
8897 return;
8898
8899 if (cp->addr.type != bdaddr_type)
8900 return;
8901
Johan Hedbergf5818c22014-12-05 13:36:02 +02008902 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008903 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008904}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008905
Marcel Holtmann445608d2013-10-06 23:55:48 -07008906void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8907 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008908{
8909 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008910
Johan Hedberg84c61d92014-08-01 11:13:30 +03008911 /* The connection is still in hci_conn_hash so test for 1
8912 * instead of 0 to know if this is the last one.
8913 */
8914 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8915 cancel_delayed_work(&hdev->power_off);
8916 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008917 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008918
Johan Hedberg4c659c32011-11-07 23:13:39 +02008919 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008920 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008921 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008922
Marcel Holtmann445608d2013-10-06 23:55:48 -07008923 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008924}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008925
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008926void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008927{
8928 struct mgmt_ev_pin_code_request ev;
8929
Johan Hedbergd8457692012-02-17 14:24:57 +02008930 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008931 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008932 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008933
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008934 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008935}
8936
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008937void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8938 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008939{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008940 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008941
Johan Hedberg333ae952015-03-17 13:48:47 +02008942 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008943 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008944 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008945
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008946 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008947 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008948}
8949
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008950void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8951 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008952{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008953 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008954
Johan Hedberg333ae952015-03-17 13:48:47 +02008955 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008956 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008957 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008958
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008959 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008960 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008961}
Johan Hedberga5c29682011-02-19 12:05:57 -03008962
Johan Hedberg744cf192011-11-08 20:40:14 +02008963int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008964 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008965 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008966{
8967 struct mgmt_ev_user_confirm_request ev;
8968
Marcel Holtmann181d6952020-05-06 09:57:47 +02008969 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008970
Johan Hedberg272d90d2012-02-09 15:26:12 +02008971 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008972 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008973 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008974 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008975
Johan Hedberg744cf192011-11-08 20:40:14 +02008976 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008977 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008978}
8979
Johan Hedberg272d90d2012-02-09 15:26:12 +02008980int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008981 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008982{
8983 struct mgmt_ev_user_passkey_request ev;
8984
Marcel Holtmann181d6952020-05-06 09:57:47 +02008985 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008986
Johan Hedberg272d90d2012-02-09 15:26:12 +02008987 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008988 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008989
8990 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008991 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008992}
8993
Brian Gix0df4c182011-11-16 13:53:13 -08008994static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008995 u8 link_type, u8 addr_type, u8 status,
8996 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008997{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008998 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008999
Johan Hedberg333ae952015-03-17 13:48:47 +02009000 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03009001 if (!cmd)
9002 return -ENOENT;
9003
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009004 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009005 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03009006
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009007 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03009008}
9009
Johan Hedberg744cf192011-11-08 20:40:14 +02009010int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009011 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009012{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009013 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009014 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009015}
9016
Johan Hedberg272d90d2012-02-09 15:26:12 +02009017int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009018 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009019{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009020 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009021 status,
9022 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009023}
Johan Hedberg2a611692011-02-19 12:06:00 -03009024
Brian Gix604086b2011-11-23 08:28:33 -08009025int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009026 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009027{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009028 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009029 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009030}
9031
Johan Hedberg272d90d2012-02-09 15:26:12 +02009032int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009033 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009034{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009035 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009036 status,
9037 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009038}
9039
Johan Hedberg92a25252012-09-06 18:39:26 +03009040int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
9041 u8 link_type, u8 addr_type, u32 passkey,
9042 u8 entered)
9043{
9044 struct mgmt_ev_passkey_notify ev;
9045
Marcel Holtmann181d6952020-05-06 09:57:47 +02009046 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03009047
9048 bacpy(&ev.addr.bdaddr, bdaddr);
9049 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9050 ev.passkey = __cpu_to_le32(passkey);
9051 ev.entered = entered;
9052
9053 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
9054}
9055
Johan Hedberge1e930f2014-09-08 17:09:49 -07009056void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03009057{
9058 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009059 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07009060 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03009061
Johan Hedberge1e930f2014-09-08 17:09:49 -07009062 bacpy(&ev.addr.bdaddr, &conn->dst);
9063 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
9064 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03009065
Johan Hedberge1e930f2014-09-08 17:09:49 -07009066 cmd = find_pairing(conn);
9067
9068 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
9069 cmd ? cmd->sk : NULL);
9070
Johan Hedberga511b352014-12-11 21:45:45 +02009071 if (cmd) {
9072 cmd->cmd_complete(cmd, status);
9073 mgmt_pending_remove(cmd);
9074 }
Johan Hedberg2a611692011-02-19 12:06:00 -03009075}
Johan Hedbergb312b1612011-03-16 14:29:37 +02009076
Marcel Holtmann464996a2013-10-15 14:26:24 -07009077void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009078{
9079 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07009080 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009081
9082 if (status) {
9083 u8 mgmt_err = mgmt_status(status);
9084 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009085 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009086 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009087 }
9088
Marcel Holtmann464996a2013-10-15 14:26:24 -07009089 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07009090 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009091 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009092 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02009093
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009094 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009095 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009096
Johan Hedberg47990ea2012-02-22 11:58:37 +02009097 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07009098 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009099
9100 if (match.sk)
9101 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009102}
9103
Johan Hedberg890ea892013-03-15 17:06:52 -05009104static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02009105{
Johan Hedberg890ea892013-03-15 17:06:52 -05009106 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009107 struct hci_cp_write_eir cp;
9108
Johan Hedberg976eb202012-10-24 21:12:01 +03009109 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05009110 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009111
Johan Hedbergc80da272012-02-22 15:38:48 +02009112 memset(hdev->eir, 0, sizeof(hdev->eir));
9113
Johan Hedbergcacaf522012-02-21 00:52:42 +02009114 memset(&cp, 0, sizeof(cp));
9115
Johan Hedberg890ea892013-03-15 17:06:52 -05009116 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02009117}
9118
Marcel Holtmann3e248562013-10-15 14:26:25 -07009119void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009120{
9121 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05009122 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009123 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009124
9125 if (status) {
9126 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009127
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009128 if (enable && hci_dev_test_and_clear_flag(hdev,
9129 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009130 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009131 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009132 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009133
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009134 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
9135 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009136 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009137 }
9138
9139 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07009140 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009141 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009142 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009143 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009144 changed = hci_dev_test_and_clear_flag(hdev,
9145 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009146 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009147 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009148 }
9149
9150 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
9151
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009152 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07009153 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009154
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02009155 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009156 sock_put(match.sk);
9157
Johan Hedberg890ea892013-03-15 17:06:52 -05009158 hci_req_init(&req, hdev);
9159
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009160 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
9161 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03009162 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
9163 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02009164 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009165 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05009166 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009167 }
Johan Hedberg890ea892013-03-15 17:06:52 -05009168
9169 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009170}
9171
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009172static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02009173{
9174 struct cmd_lookup *match = data;
9175
Johan Hedberg90e70452012-02-23 23:09:40 +02009176 if (match->sk == NULL) {
9177 match->sk = cmd->sk;
9178 sock_hold(match->sk);
9179 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009180}
9181
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07009182void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
9183 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009184{
Johan Hedberg90e70452012-02-23 23:09:40 +02009185 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009186
Johan Hedberg92da6092013-03-15 17:06:55 -05009187 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
9188 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
9189 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02009190
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009191 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009192 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
9193 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009194 ext_info_changed(hdev, NULL);
9195 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009196
9197 if (match.sk)
9198 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009199}
9200
Marcel Holtmann7667da32013-10-15 14:26:27 -07009201void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02009202{
Johan Hedbergb312b1612011-03-16 14:29:37 +02009203 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009204 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009205
Johan Hedberg13928972013-03-15 17:07:00 -05009206 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07009207 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009208
9209 memset(&ev, 0, sizeof(ev));
9210 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009211 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009212
Johan Hedberg333ae952015-03-17 13:48:47 +02009213 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05009214 if (!cmd) {
9215 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02009216
Johan Hedberg13928972013-03-15 17:07:00 -05009217 /* If this is a HCI command related to powering on the
9218 * HCI dev don't send any mgmt signals.
9219 */
Johan Hedberg333ae952015-03-17 13:48:47 +02009220 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07009221 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009222 }
9223
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009224 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
9225 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009226 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009227}
Szymon Jancc35938b2011-03-22 13:12:21 +01009228
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009229static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
9230{
9231 int i;
9232
9233 for (i = 0; i < uuid_count; i++) {
9234 if (!memcmp(uuid, uuids[i], 16))
9235 return true;
9236 }
9237
9238 return false;
9239}
9240
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009241static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
9242{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009243 u16 parsed = 0;
9244
9245 while (parsed < eir_len) {
9246 u8 field_len = eir[0];
9247 u8 uuid[16];
9248 int i;
9249
9250 if (field_len == 0)
9251 break;
9252
9253 if (eir_len - parsed < field_len + 1)
9254 break;
9255
9256 switch (eir[1]) {
9257 case EIR_UUID16_ALL:
9258 case EIR_UUID16_SOME:
9259 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009260 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009261 uuid[13] = eir[i + 3];
9262 uuid[12] = eir[i + 2];
9263 if (has_uuid(uuid, uuid_count, uuids))
9264 return true;
9265 }
9266 break;
9267 case EIR_UUID32_ALL:
9268 case EIR_UUID32_SOME:
9269 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009270 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009271 uuid[15] = eir[i + 5];
9272 uuid[14] = eir[i + 4];
9273 uuid[13] = eir[i + 3];
9274 uuid[12] = eir[i + 2];
9275 if (has_uuid(uuid, uuid_count, uuids))
9276 return true;
9277 }
9278 break;
9279 case EIR_UUID128_ALL:
9280 case EIR_UUID128_SOME:
9281 for (i = 0; i + 17 <= field_len; i += 16) {
9282 memcpy(uuid, eir + i + 2, 16);
9283 if (has_uuid(uuid, uuid_count, uuids))
9284 return true;
9285 }
9286 break;
9287 }
9288
9289 parsed += field_len + 1;
9290 eir += field_len + 1;
9291 }
9292
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009293 return false;
9294}
9295
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009296static void restart_le_scan(struct hci_dev *hdev)
9297{
9298 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009299 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009300 return;
9301
9302 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
9303 hdev->discovery.scan_start +
9304 hdev->discovery.scan_duration))
9305 return;
9306
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02009307 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009308 DISCOV_LE_RESTART_DELAY);
9309}
9310
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009311static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
9312 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
9313{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009314 /* If a RSSI threshold has been specified, and
9315 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
9316 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
9317 * is set, let it through for further processing, as we might need to
9318 * restart the scan.
9319 *
9320 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
9321 * the results are also dropped.
9322 */
9323 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9324 (rssi == HCI_RSSI_INVALID ||
9325 (rssi < hdev->discovery.rssi &&
9326 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
9327 return false;
9328
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009329 if (hdev->discovery.uuid_count != 0) {
9330 /* If a list of UUIDs is provided in filter, results with no
9331 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009332 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009333 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
9334 hdev->discovery.uuids) &&
9335 !eir_has_uuids(scan_rsp, scan_rsp_len,
9336 hdev->discovery.uuid_count,
9337 hdev->discovery.uuids))
9338 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009339 }
9340
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009341 /* If duplicate filtering does not report RSSI changes, then restart
9342 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009343 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009344 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
9345 restart_le_scan(hdev);
9346
9347 /* Validate RSSI value against the RSSI threshold once more. */
9348 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9349 rssi < hdev->discovery.rssi)
9350 return false;
9351 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009352
9353 return true;
9354}
9355
Marcel Holtmann901801b2013-10-06 23:55:51 -07009356void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02009357 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
9358 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03009359{
Johan Hedberge319d2e2012-01-15 19:51:59 +02009360 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009361 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02009362 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03009363
Johan Hedberg75ce2082014-07-02 22:42:01 +03009364 /* Don't send events for a non-kernel initiated discovery. With
9365 * LE one exception is if we have pend_le_reports > 0 in which
9366 * case we're doing passive scanning and want these events.
9367 */
9368 if (!hci_discovery_active(hdev)) {
9369 if (link_type == ACL_LINK)
9370 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009371 if (link_type == LE_LINK &&
9372 list_empty(&hdev->pend_le_reports) &&
9373 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03009374 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009375 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03009376 }
Andre Guedes12602d02013-04-30 15:29:40 -03009377
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08009378 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009379 /* We are using service discovery */
9380 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
9381 scan_rsp_len))
9382 return;
9383 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01009384
Johan Hedberg78b781c2016-01-05 13:19:32 +02009385 if (hdev->discovery.limited) {
9386 /* Check for limited discoverable bit */
9387 if (dev_class) {
9388 if (!(dev_class[1] & 0x20))
9389 return;
9390 } else {
9391 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
9392 if (!flags || !(flags[0] & LE_AD_LIMITED))
9393 return;
9394 }
9395 }
9396
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009397 /* Make sure that the buffer is big enough. The 5 extra bytes
9398 * are for the potential CoD field.
9399 */
9400 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07009401 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03009402
Johan Hedberg1dc06092012-01-15 21:01:23 +02009403 memset(buf, 0, sizeof(buf));
9404
Marcel Holtmannda25cf62014-12-05 13:03:35 +01009405 /* In case of device discovery with BR/EDR devices (pre 1.2), the
9406 * RSSI value was reported as 0 when not available. This behavior
9407 * is kept when using device discovery. This is required for full
9408 * backwards compatibility with the API.
9409 *
9410 * However when using service discovery, the value 127 will be
9411 * returned when the RSSI is not available.
9412 */
Szymon Janc91200e92015-01-22 16:57:05 +01009413 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
9414 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01009415 rssi = 0;
9416
Johan Hedberg841c5642014-07-07 12:45:54 +03009417 bacpy(&ev->addr.bdaddr, bdaddr);
9418 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02009419 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02009420 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03009421
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009422 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009423 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02009424 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03009425
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02009426 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
9427 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02009428 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009429 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02009430
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009431 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009432 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009433 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009434
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009435 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
9436 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03009437
Marcel Holtmann901801b2013-10-06 23:55:51 -07009438 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03009439}
Johan Hedberga88a9652011-03-30 13:18:12 +03009440
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009441void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9442 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03009443{
Johan Hedbergb644ba32012-01-17 21:48:47 +02009444 struct mgmt_ev_device_found *ev;
9445 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
9446 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03009447
Johan Hedbergb644ba32012-01-17 21:48:47 +02009448 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03009449
Johan Hedbergb644ba32012-01-17 21:48:47 +02009450 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03009451
Johan Hedbergb644ba32012-01-17 21:48:47 +02009452 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009453 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009454 ev->rssi = rssi;
9455
9456 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009457 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009458
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009459 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009460
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009461 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03009462}
Johan Hedberg314b2382011-04-27 10:29:57 -04009463
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009464void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04009465{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009466 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02009467
Marcel Holtmann181d6952020-05-06 09:57:47 +02009468 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03009469
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009470 memset(&ev, 0, sizeof(ev));
9471 ev.type = hdev->discovery.type;
9472 ev.discovering = discovering;
9473
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009474 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04009475}
Antti Julku5e762442011-08-25 16:48:02 +03009476
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07009477void mgmt_suspending(struct hci_dev *hdev, u8 state)
9478{
9479 struct mgmt_ev_controller_suspend ev;
9480
9481 ev.suspend_state = state;
9482 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
9483}
9484
9485void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
9486 u8 addr_type)
9487{
9488 struct mgmt_ev_controller_resume ev;
9489
9490 ev.wake_reason = reason;
9491 if (bdaddr) {
9492 bacpy(&ev.addr.bdaddr, bdaddr);
9493 ev.addr.type = addr_type;
9494 } else {
9495 memset(&ev.addr, 0, sizeof(ev.addr));
9496 }
9497
9498 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
9499}
9500
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009501static struct hci_mgmt_chan chan = {
9502 .channel = HCI_CHANNEL_CONTROL,
9503 .handler_count = ARRAY_SIZE(mgmt_handlers),
9504 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02009505 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009506};
9507
9508int mgmt_init(void)
9509{
9510 return hci_mgmt_chan_register(&chan);
9511}
9512
9513void mgmt_exit(void)
9514{
9515 hci_mgmt_chan_unregister(&chan);
9516}