blob: 1eca36e51706ea59cf06dac0c5020c5f87f1686e [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 Holtmann3679fe72020-04-03 21:44:06 +020043#define MGMT_REVISION 17
Johan Hedberg02d98122010-12-13 21:07:04 +020044
Johan Hedberge70bb2e2012-02-13 16:59:33 +020045static const u16 mgmt_commands[] = {
46 MGMT_OP_READ_INDEX_LIST,
47 MGMT_OP_READ_INFO,
48 MGMT_OP_SET_POWERED,
49 MGMT_OP_SET_DISCOVERABLE,
50 MGMT_OP_SET_CONNECTABLE,
51 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030052 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020053 MGMT_OP_SET_LINK_SECURITY,
54 MGMT_OP_SET_SSP,
55 MGMT_OP_SET_HS,
56 MGMT_OP_SET_LE,
57 MGMT_OP_SET_DEV_CLASS,
58 MGMT_OP_SET_LOCAL_NAME,
59 MGMT_OP_ADD_UUID,
60 MGMT_OP_REMOVE_UUID,
61 MGMT_OP_LOAD_LINK_KEYS,
62 MGMT_OP_LOAD_LONG_TERM_KEYS,
63 MGMT_OP_DISCONNECT,
64 MGMT_OP_GET_CONNECTIONS,
65 MGMT_OP_PIN_CODE_REPLY,
66 MGMT_OP_PIN_CODE_NEG_REPLY,
67 MGMT_OP_SET_IO_CAPABILITY,
68 MGMT_OP_PAIR_DEVICE,
69 MGMT_OP_CANCEL_PAIR_DEVICE,
70 MGMT_OP_UNPAIR_DEVICE,
71 MGMT_OP_USER_CONFIRM_REPLY,
72 MGMT_OP_USER_CONFIRM_NEG_REPLY,
73 MGMT_OP_USER_PASSKEY_REPLY,
74 MGMT_OP_USER_PASSKEY_NEG_REPLY,
75 MGMT_OP_READ_LOCAL_OOB_DATA,
76 MGMT_OP_ADD_REMOTE_OOB_DATA,
77 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
78 MGMT_OP_START_DISCOVERY,
79 MGMT_OP_STOP_DISCOVERY,
80 MGMT_OP_CONFIRM_NAME,
81 MGMT_OP_BLOCK_DEVICE,
82 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070083 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030084 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030085 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070086 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070087 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080088 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080089 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020090 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020091 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020092 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030093 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020094 MGMT_OP_ADD_DEVICE,
95 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030096 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020097 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020098 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020099 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200100 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100101 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700102 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700103 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700104 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700105 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700106 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100107 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200108 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200109 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200110 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000111 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000112 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200113 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200114 MGMT_OP_READ_EXP_FEATURES_INFO,
115 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000116 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
117 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200118 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
119 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200120 MGMT_OP_GET_DEVICE_FLAGS,
121 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200122 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200123 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200124};
125
126static const u16 mgmt_events[] = {
127 MGMT_EV_CONTROLLER_ERROR,
128 MGMT_EV_INDEX_ADDED,
129 MGMT_EV_INDEX_REMOVED,
130 MGMT_EV_NEW_SETTINGS,
131 MGMT_EV_CLASS_OF_DEV_CHANGED,
132 MGMT_EV_LOCAL_NAME_CHANGED,
133 MGMT_EV_NEW_LINK_KEY,
134 MGMT_EV_NEW_LONG_TERM_KEY,
135 MGMT_EV_DEVICE_CONNECTED,
136 MGMT_EV_DEVICE_DISCONNECTED,
137 MGMT_EV_CONNECT_FAILED,
138 MGMT_EV_PIN_CODE_REQUEST,
139 MGMT_EV_USER_CONFIRM_REQUEST,
140 MGMT_EV_USER_PASSKEY_REQUEST,
141 MGMT_EV_AUTH_FAILED,
142 MGMT_EV_DEVICE_FOUND,
143 MGMT_EV_DISCOVERING,
144 MGMT_EV_DEVICE_BLOCKED,
145 MGMT_EV_DEVICE_UNBLOCKED,
146 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300147 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800148 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700149 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200150 MGMT_EV_DEVICE_ADDED,
151 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300152 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200153 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200154 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200155 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700156 MGMT_EV_EXT_INDEX_ADDED,
157 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700158 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700159 MGMT_EV_ADVERTISING_ADDED,
160 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200161 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200162 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200163 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200164 MGMT_EV_DEVICE_FLAGS_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200165};
166
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700167static const u16 mgmt_untrusted_commands[] = {
168 MGMT_OP_READ_INDEX_LIST,
169 MGMT_OP_READ_INFO,
170 MGMT_OP_READ_UNCONF_INDEX_LIST,
171 MGMT_OP_READ_CONFIG_INFO,
172 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200173 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200174 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200175 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000176 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200177 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700178};
179
180static const u16 mgmt_untrusted_events[] = {
181 MGMT_EV_INDEX_ADDED,
182 MGMT_EV_INDEX_REMOVED,
183 MGMT_EV_NEW_SETTINGS,
184 MGMT_EV_CLASS_OF_DEV_CHANGED,
185 MGMT_EV_LOCAL_NAME_CHANGED,
186 MGMT_EV_UNCONF_INDEX_ADDED,
187 MGMT_EV_UNCONF_INDEX_REMOVED,
188 MGMT_EV_NEW_CONFIG_OPTIONS,
189 MGMT_EV_EXT_INDEX_ADDED,
190 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200191 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200192 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700193};
194
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800195#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200196
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200197#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
198 "\x00\x00\x00\x00\x00\x00\x00\x00"
199
Johan Hedbergca69b792011-11-11 18:10:00 +0200200/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000201static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200202 MGMT_STATUS_SUCCESS,
203 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
204 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
205 MGMT_STATUS_FAILED, /* Hardware Failure */
206 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
207 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200208 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200209 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
210 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
211 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
212 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
213 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
214 MGMT_STATUS_BUSY, /* Command Disallowed */
215 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
216 MGMT_STATUS_REJECTED, /* Rejected Security */
217 MGMT_STATUS_REJECTED, /* Rejected Personal */
218 MGMT_STATUS_TIMEOUT, /* Host Timeout */
219 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
220 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
221 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
222 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
223 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
224 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
225 MGMT_STATUS_BUSY, /* Repeated Attempts */
226 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
227 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
228 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
229 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
230 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
231 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
232 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
233 MGMT_STATUS_FAILED, /* Unspecified Error */
234 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
235 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
236 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
237 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
238 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
239 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
240 MGMT_STATUS_FAILED, /* Unit Link Key Used */
241 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
242 MGMT_STATUS_TIMEOUT, /* Instant Passed */
243 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
244 MGMT_STATUS_FAILED, /* Transaction Collision */
245 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
246 MGMT_STATUS_REJECTED, /* QoS Rejected */
247 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
248 MGMT_STATUS_REJECTED, /* Insufficient Security */
249 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
250 MGMT_STATUS_BUSY, /* Role Switch Pending */
251 MGMT_STATUS_FAILED, /* Slot Violation */
252 MGMT_STATUS_FAILED, /* Role Switch Failed */
253 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
254 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
255 MGMT_STATUS_BUSY, /* Host Busy Pairing */
256 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
257 MGMT_STATUS_BUSY, /* Controller Busy */
258 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
259 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
260 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
261 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
262 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
263};
264
265static u8 mgmt_status(u8 hci_status)
266{
267 if (hci_status < ARRAY_SIZE(mgmt_status_table))
268 return mgmt_status_table[hci_status];
269
270 return MGMT_STATUS_FAILED;
271}
272
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700273static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
274 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700275{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700276 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
277 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700278}
279
Marcel Holtmann72000df2015-03-16 16:11:21 -0700280static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
281 u16 len, int flag, struct sock *skip_sk)
282{
283 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
284 flag, skip_sk);
285}
286
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200287static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
288 struct sock *skip_sk)
289{
290 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700291 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200292}
293
Johan Hedberg85813a72015-10-21 18:02:59 +0300294static u8 le_addr_type(u8 mgmt_addr_type)
295{
296 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
297 return ADDR_LE_DEV_PUBLIC;
298 else
299 return ADDR_LE_DEV_RANDOM;
300}
301
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200302void mgmt_fill_version_info(void *ver)
303{
304 struct mgmt_rp_read_version *rp = ver;
305
306 rp->version = MGMT_VERSION;
307 rp->revision = cpu_to_le16(MGMT_REVISION);
308}
309
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
311 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200312{
313 struct mgmt_rp_read_version rp;
314
Marcel Holtmann181d6952020-05-06 09:57:47 +0200315 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200316
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200317 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200318
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200319 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
320 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200321}
322
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300323static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
324 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200325{
326 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700327 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328 size_t rp_size;
329 int i, err;
330
Marcel Holtmann181d6952020-05-06 09:57:47 +0200331 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200332
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700333 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
334 num_commands = ARRAY_SIZE(mgmt_commands);
335 num_events = ARRAY_SIZE(mgmt_events);
336 } else {
337 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
338 num_events = ARRAY_SIZE(mgmt_untrusted_events);
339 }
340
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
342
343 rp = kmalloc(rp_size, GFP_KERNEL);
344 if (!rp)
345 return -ENOMEM;
346
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700347 rp->num_commands = cpu_to_le16(num_commands);
348 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200349
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700350 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
351 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200352
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700353 for (i = 0; i < num_commands; i++, opcode++)
354 put_unaligned_le16(mgmt_commands[i], opcode);
355
356 for (i = 0; i < num_events; i++, opcode++)
357 put_unaligned_le16(mgmt_events[i], opcode);
358 } else {
359 __le16 *opcode = rp->opcodes;
360
361 for (i = 0; i < num_commands; i++, opcode++)
362 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
363
364 for (i = 0; i < num_events; i++, opcode++)
365 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
366 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200367
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200368 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
369 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200370 kfree(rp);
371
372 return err;
373}
374
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300375static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
376 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200377{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200379 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200380 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200381 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300382 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200383
Marcel Holtmann181d6952020-05-06 09:57:47 +0200384 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200385
386 read_lock(&hci_dev_list_lock);
387
388 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300389 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200390 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700391 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700392 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200393 }
394
Johan Hedberga38528f2011-01-22 06:46:43 +0200395 rp_len = sizeof(*rp) + (2 * count);
396 rp = kmalloc(rp_len, GFP_ATOMIC);
397 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100398 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200399 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100400 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401
Johan Hedberg476e44c2012-10-19 20:10:46 +0300402 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200403 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700404 if (hci_dev_test_flag(d, HCI_SETUP) ||
405 hci_dev_test_flag(d, HCI_CONFIG) ||
406 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200407 continue;
408
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200409 /* Devices marked as raw-only are neither configured
410 * nor unconfigured controllers.
411 */
412 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700413 continue;
414
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200415 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700416 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700417 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200418 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700419 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200420 }
421
Johan Hedberg476e44c2012-10-19 20:10:46 +0300422 rp->num_controllers = cpu_to_le16(count);
423 rp_len = sizeof(*rp) + (2 * count);
424
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200425 read_unlock(&hci_dev_list_lock);
426
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200427 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
428 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200429
Johan Hedberga38528f2011-01-22 06:46:43 +0200430 kfree(rp);
431
432 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200433}
434
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200435static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
436 void *data, u16 data_len)
437{
438 struct mgmt_rp_read_unconf_index_list *rp;
439 struct hci_dev *d;
440 size_t rp_len;
441 u16 count;
442 int err;
443
Marcel Holtmann181d6952020-05-06 09:57:47 +0200444 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200445
446 read_lock(&hci_dev_list_lock);
447
448 count = 0;
449 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200450 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700451 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200452 count++;
453 }
454
455 rp_len = sizeof(*rp) + (2 * count);
456 rp = kmalloc(rp_len, GFP_ATOMIC);
457 if (!rp) {
458 read_unlock(&hci_dev_list_lock);
459 return -ENOMEM;
460 }
461
462 count = 0;
463 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700464 if (hci_dev_test_flag(d, HCI_SETUP) ||
465 hci_dev_test_flag(d, HCI_CONFIG) ||
466 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200467 continue;
468
469 /* Devices marked as raw-only are neither configured
470 * nor unconfigured controllers.
471 */
472 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
473 continue;
474
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200475 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700476 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200477 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200478 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200479 }
480 }
481
482 rp->num_controllers = cpu_to_le16(count);
483 rp_len = sizeof(*rp) + (2 * count);
484
485 read_unlock(&hci_dev_list_lock);
486
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200487 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
488 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200489
490 kfree(rp);
491
492 return err;
493}
494
Marcel Holtmann96f14742015-03-14 19:27:57 -0700495static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
496 void *data, u16 data_len)
497{
498 struct mgmt_rp_read_ext_index_list *rp;
499 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700500 u16 count;
501 int err;
502
Marcel Holtmann181d6952020-05-06 09:57:47 +0200503 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700504
505 read_lock(&hci_dev_list_lock);
506
507 count = 0;
508 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200509 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700510 count++;
511 }
512
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600513 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700514 if (!rp) {
515 read_unlock(&hci_dev_list_lock);
516 return -ENOMEM;
517 }
518
519 count = 0;
520 list_for_each_entry(d, &hci_dev_list, list) {
521 if (hci_dev_test_flag(d, HCI_SETUP) ||
522 hci_dev_test_flag(d, HCI_CONFIG) ||
523 hci_dev_test_flag(d, HCI_USER_CHANNEL))
524 continue;
525
526 /* Devices marked as raw-only are neither configured
527 * nor unconfigured controllers.
528 */
529 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
530 continue;
531
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200532 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700533 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
534 rp->entry[count].type = 0x01;
535 else
536 rp->entry[count].type = 0x00;
537 } else if (d->dev_type == HCI_AMP) {
538 rp->entry[count].type = 0x02;
539 } else {
540 continue;
541 }
542
543 rp->entry[count].bus = d->bus;
544 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200545 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700546 }
547
548 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700549
550 read_unlock(&hci_dev_list_lock);
551
552 /* If this command is called at least once, then all the
553 * default index and unconfigured index events are disabled
554 * and from now on only extended index events are used.
555 */
556 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
557 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
558 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
559
560 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600561 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
562 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700563
564 kfree(rp);
565
566 return err;
567}
568
Marcel Holtmanndbece372014-07-04 18:11:55 +0200569static bool is_configured(struct hci_dev *hdev)
570{
571 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700572 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200573 return false;
574
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800575 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
576 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200577 !bacmp(&hdev->public_addr, BDADDR_ANY))
578 return false;
579
580 return true;
581}
582
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200583static __le32 get_missing_options(struct hci_dev *hdev)
584{
585 u32 options = 0;
586
Marcel Holtmanndbece372014-07-04 18:11:55 +0200587 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700588 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200589 options |= MGMT_OPTION_EXTERNAL_CONFIG;
590
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800591 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
592 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200593 !bacmp(&hdev->public_addr, BDADDR_ANY))
594 options |= MGMT_OPTION_PUBLIC_ADDRESS;
595
596 return cpu_to_le32(options);
597}
598
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200599static int new_options(struct hci_dev *hdev, struct sock *skip)
600{
601 __le32 options = get_missing_options(hdev);
602
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200603 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
604 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200605}
606
Marcel Holtmanndbece372014-07-04 18:11:55 +0200607static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
608{
609 __le32 options = get_missing_options(hdev);
610
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200611 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
612 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200613}
614
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200615static int read_config_info(struct sock *sk, struct hci_dev *hdev,
616 void *data, u16 data_len)
617{
618 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200619 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200620
Marcel Holtmann181d6952020-05-06 09:57:47 +0200621 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200622
623 hci_dev_lock(hdev);
624
625 memset(&rp, 0, sizeof(rp));
626 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200627
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200628 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
629 options |= MGMT_OPTION_EXTERNAL_CONFIG;
630
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200631 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200632 options |= MGMT_OPTION_PUBLIC_ADDRESS;
633
634 rp.supported_options = cpu_to_le32(options);
635 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200636
637 hci_dev_unlock(hdev);
638
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200639 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
640 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200641}
642
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530643static u32 get_supported_phys(struct hci_dev *hdev)
644{
645 u32 supported_phys = 0;
646
647 if (lmp_bredr_capable(hdev)) {
648 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
649
650 if (hdev->features[0][0] & LMP_3SLOT)
651 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
652
653 if (hdev->features[0][0] & LMP_5SLOT)
654 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
655
656 if (lmp_edr_2m_capable(hdev)) {
657 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
658
659 if (lmp_edr_3slot_capable(hdev))
660 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
661
662 if (lmp_edr_5slot_capable(hdev))
663 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
664
665 if (lmp_edr_3m_capable(hdev)) {
666 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
667
668 if (lmp_edr_3slot_capable(hdev))
669 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
670
671 if (lmp_edr_5slot_capable(hdev))
672 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
673 }
674 }
675 }
676
677 if (lmp_le_capable(hdev)) {
678 supported_phys |= MGMT_PHY_LE_1M_TX;
679 supported_phys |= MGMT_PHY_LE_1M_RX;
680
681 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
682 supported_phys |= MGMT_PHY_LE_2M_TX;
683 supported_phys |= MGMT_PHY_LE_2M_RX;
684 }
685
686 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
687 supported_phys |= MGMT_PHY_LE_CODED_TX;
688 supported_phys |= MGMT_PHY_LE_CODED_RX;
689 }
690 }
691
692 return supported_phys;
693}
694
695static u32 get_selected_phys(struct hci_dev *hdev)
696{
697 u32 selected_phys = 0;
698
699 if (lmp_bredr_capable(hdev)) {
700 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
701
702 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
703 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
704
705 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
706 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
707
708 if (lmp_edr_2m_capable(hdev)) {
709 if (!(hdev->pkt_type & HCI_2DH1))
710 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
711
712 if (lmp_edr_3slot_capable(hdev) &&
713 !(hdev->pkt_type & HCI_2DH3))
714 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
715
716 if (lmp_edr_5slot_capable(hdev) &&
717 !(hdev->pkt_type & HCI_2DH5))
718 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
719
720 if (lmp_edr_3m_capable(hdev)) {
721 if (!(hdev->pkt_type & HCI_3DH1))
722 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
723
724 if (lmp_edr_3slot_capable(hdev) &&
725 !(hdev->pkt_type & HCI_3DH3))
726 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
727
728 if (lmp_edr_5slot_capable(hdev) &&
729 !(hdev->pkt_type & HCI_3DH5))
730 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
731 }
732 }
733 }
734
735 if (lmp_le_capable(hdev)) {
736 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
737 selected_phys |= MGMT_PHY_LE_1M_TX;
738
739 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
740 selected_phys |= MGMT_PHY_LE_1M_RX;
741
742 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
743 selected_phys |= MGMT_PHY_LE_2M_TX;
744
745 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
746 selected_phys |= MGMT_PHY_LE_2M_RX;
747
748 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
749 selected_phys |= MGMT_PHY_LE_CODED_TX;
750
751 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
752 selected_phys |= MGMT_PHY_LE_CODED_RX;
753 }
754
755 return selected_phys;
756}
757
758static u32 get_configurable_phys(struct hci_dev *hdev)
759{
760 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
761 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
762}
763
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200764static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200765{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200766 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200767
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200768 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300769 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800770 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300771 settings |= MGMT_SETTING_CONNECTABLE;
772 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Andre Guedesed3fa312012-07-24 15:03:46 -0300774 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500775 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
776 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200777 settings |= MGMT_SETTING_BREDR;
778 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700779
780 if (lmp_ssp_capable(hdev)) {
781 settings |= MGMT_SETTING_SSP;
782 settings |= MGMT_SETTING_HS;
783 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800784
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800785 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800786 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000787
Alain Michaud00bce3f2020-03-05 16:14:59 +0000788 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000789 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000790 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700791 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100792
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300793 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200794 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300795 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300796 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200797 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800798 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300799 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200800
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200801 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
802 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200803 settings |= MGMT_SETTING_CONFIGURATION;
804
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530805 settings |= MGMT_SETTING_PHY_CONFIGURATION;
806
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200807 return settings;
808}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200809
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200810static u32 get_current_settings(struct hci_dev *hdev)
811{
812 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200813
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200814 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100815 settings |= MGMT_SETTING_POWERED;
816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700817 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200818 settings |= MGMT_SETTING_CONNECTABLE;
819
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700820 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500821 settings |= MGMT_SETTING_FAST_CONNECTABLE;
822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700823 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200824 settings |= MGMT_SETTING_DISCOVERABLE;
825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700826 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300827 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700829 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200830 settings |= MGMT_SETTING_BREDR;
831
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700832 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200834
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700835 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200836 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200837
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700838 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200839 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200840
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700841 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200842 settings |= MGMT_SETTING_HS;
843
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700844 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300845 settings |= MGMT_SETTING_ADVERTISING;
846
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700847 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800848 settings |= MGMT_SETTING_SECURE_CONN;
849
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700850 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800851 settings |= MGMT_SETTING_DEBUG_KEYS;
852
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700853 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200854 settings |= MGMT_SETTING_PRIVACY;
855
Marcel Holtmann93690c22015-03-06 10:11:21 -0800856 /* The current setting for static address has two purposes. The
857 * first is to indicate if the static address will be used and
858 * the second is to indicate if it is actually set.
859 *
860 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700861 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800862 * address is actually used decides if the flag is set or not.
863 *
864 * For single mode LE only controllers and dual-mode controllers
865 * with BR/EDR disabled, the existence of the static address will
866 * be evaluated.
867 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700868 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700869 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800870 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
871 if (bacmp(&hdev->static_addr, BDADDR_ANY))
872 settings |= MGMT_SETTING_STATIC_ADDRESS;
873 }
874
Alain Michaud00bce3f2020-03-05 16:14:59 +0000875 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
876 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
877
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200878 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200879}
880
Johan Hedberg333ae952015-03-17 13:48:47 +0200881static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
882{
883 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
884}
885
Johan Hedberg333ae952015-03-17 13:48:47 +0200886static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
887 struct hci_dev *hdev,
888 const void *data)
889{
890 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
891}
892
Johan Hedbergf2252572015-11-18 12:49:20 +0200893u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300894{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200895 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300896
897 /* If there's a pending mgmt command the flags will not yet have
898 * their final values, so check for this first.
899 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200900 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300901 if (cmd) {
902 struct mgmt_mode *cp = cmd->param;
903 if (cp->val == 0x01)
904 return LE_AD_GENERAL;
905 else if (cp->val == 0x02)
906 return LE_AD_LIMITED;
907 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700908 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300909 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700910 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300911 return LE_AD_GENERAL;
912 }
913
914 return 0;
915}
916
Johan Hedbergf2252572015-11-18 12:49:20 +0200917bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700918{
919 struct mgmt_pending_cmd *cmd;
920
921 /* If there's a pending mgmt command the flag will not yet have
922 * it's final value, so check for this first.
923 */
924 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
925 if (cmd) {
926 struct mgmt_mode *cp = cmd->param;
927
928 return cp->val;
929 }
930
931 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
932}
933
Johan Hedberg7d785252011-12-15 00:47:39 +0200934static void service_cache_off(struct work_struct *work)
935{
936 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300937 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500938 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200939
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700940 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200941 return;
942
Johan Hedberg890ea892013-03-15 17:06:52 -0500943 hci_req_init(&req, hdev);
944
Johan Hedberg7d785252011-12-15 00:47:39 +0200945 hci_dev_lock(hdev);
946
Johan Hedbergb1a89172015-11-25 16:15:42 +0200947 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200948 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200949
950 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500951
952 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200953}
954
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200955static void rpa_expired(struct work_struct *work)
956{
957 struct hci_dev *hdev = container_of(work, struct hci_dev,
958 rpa_expired.work);
959 struct hci_request req;
960
Marcel Holtmann181d6952020-05-06 09:57:47 +0200961 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200962
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700963 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200964
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700965 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200966 return;
967
968 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200969 * controller happens in the hci_req_enable_advertising()
970 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200971 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200972 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530973 if (ext_adv_capable(hdev))
974 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
975 else
976 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200977 hci_req_run(&req, NULL);
978}
979
Johan Hedberg6a919082012-02-28 06:17:26 +0200980static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200981{
Marcel Holtmann238be782015-03-13 02:11:06 -0700982 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200983 return;
984
Johan Hedberg4f87da82012-03-02 19:55:56 +0200985 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200986 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200987
Johan Hedberg4f87da82012-03-02 19:55:56 +0200988 /* Non-mgmt controlled devices get this bit set
989 * implicitly so that pairing works for them, however
990 * for mgmt we require user-space to explicitly enable
991 * it
992 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700993 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200994}
995
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200996static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300997 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200998{
999 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001000
Marcel Holtmann181d6952020-05-06 09:57:47 +02001001 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001002
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001003 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001004
Johan Hedberg03811012010-12-08 00:21:06 +02001005 memset(&rp, 0, sizeof(rp));
1006
Johan Hedberg03811012010-12-08 00:21:06 +02001007 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001008
1009 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001010 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001011
1012 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1013 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1014
1015 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001016
1017 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001018 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001019
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001020 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001021
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001022 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1023 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001024}
1025
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001026static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1027{
1028 u16 eir_len = 0;
1029 size_t name_len;
1030
1031 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1032 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1033 hdev->dev_class, 3);
1034
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001035 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1036 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1037 hdev->appearance);
1038
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001039 name_len = strlen(hdev->dev_name);
1040 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1041 hdev->dev_name, name_len);
1042
1043 name_len = strlen(hdev->short_name);
1044 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1045 hdev->short_name, name_len);
1046
1047 return eir_len;
1048}
1049
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001050static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1051 void *data, u16 data_len)
1052{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001053 char buf[512];
1054 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001055 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001056
Marcel Holtmann181d6952020-05-06 09:57:47 +02001057 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001058
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001059 memset(&buf, 0, sizeof(buf));
1060
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001061 hci_dev_lock(hdev);
1062
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001063 bacpy(&rp->bdaddr, &hdev->bdaddr);
1064
1065 rp->version = hdev->hci_ver;
1066 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1067
1068 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1069 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001070
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001071
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001072 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001073 rp->eir_len = cpu_to_le16(eir_len);
1074
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001075 hci_dev_unlock(hdev);
1076
1077 /* If this command is called at least once, then the events
1078 * for class of device and local name changes are disabled
1079 * and only the new extended controller information event
1080 * is used.
1081 */
1082 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1083 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1084 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1085
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001086 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1087 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001088}
1089
1090static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1091{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001092 char buf[512];
1093 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1094 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001095
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001096 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001097
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001098 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1099 ev->eir_len = cpu_to_le16(eir_len);
1100
1101 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1102 sizeof(*ev) + eir_len,
1103 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001104}
1105
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001106static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001107{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001108 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001109
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001110 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1111 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001112}
1113
Marcel Holtmann1904a852015-01-11 13:50:44 -08001114static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001115{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001116 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001117
Johan Hedberga3172b72014-02-28 09:33:44 +02001118 if (hci_conn_count(hdev) == 0) {
1119 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001120 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001121 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001122}
1123
Johan Hedbergf2252572015-11-18 12:49:20 +02001124void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001125{
1126 struct mgmt_ev_advertising_added ev;
1127
1128 ev.instance = instance;
1129
1130 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1131}
1132
Johan Hedbergf2252572015-11-18 12:49:20 +02001133void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1134 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001135{
1136 struct mgmt_ev_advertising_removed ev;
1137
1138 ev.instance = instance;
1139
1140 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1141}
1142
Florian Grandel7816b822015-06-18 03:16:45 +02001143static void cancel_adv_timeout(struct hci_dev *hdev)
1144{
1145 if (hdev->adv_instance_timeout) {
1146 hdev->adv_instance_timeout = 0;
1147 cancel_delayed_work(&hdev->adv_instance_expire);
1148 }
1149}
1150
Johan Hedberg8b064a32014-02-24 14:52:22 +02001151static int clean_up_hci_state(struct hci_dev *hdev)
1152{
1153 struct hci_request req;
1154 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001155 bool discov_stopped;
1156 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001157
1158 hci_req_init(&req, hdev);
1159
1160 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1161 test_bit(HCI_PSCAN, &hdev->flags)) {
1162 u8 scan = 0x00;
1163 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1164 }
1165
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001166 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001167
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001168 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001169 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001170
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001171 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001172
1173 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001174 /* 0x15 == Terminated due to Power Off */
1175 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001176 }
1177
Johan Hedberg23a48092014-07-08 16:05:06 +03001178 err = hci_req_run(&req, clean_up_hci_complete);
1179 if (!err && discov_stopped)
1180 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1181
1182 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001183}
1184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001185static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001186 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001188 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001189 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001190 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191
Marcel Holtmann181d6952020-05-06 09:57:47 +02001192 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
Johan Hedberga7e80f22013-01-09 16:05:19 +02001194 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001195 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1196 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001197
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001198 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199
Johan Hedberg333ae952015-03-17 13:48:47 +02001200 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001201 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1202 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001203 goto failed;
1204 }
1205
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001206 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001207 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208 goto failed;
1209 }
1210
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1212 if (!cmd) {
1213 err = -ENOMEM;
1214 goto failed;
1215 }
1216
Johan Hedberg8b064a32014-02-24 14:52:22 +02001217 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001218 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001219 err = 0;
1220 } else {
1221 /* Disconnect connections, stop scans, etc */
1222 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001223 if (!err)
1224 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1225 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001226
Johan Hedberg8b064a32014-02-24 14:52:22 +02001227 /* ENODATA means there were no HCI commands queued */
1228 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001229 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001230 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1231 err = 0;
1232 }
1233 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001234
1235failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001236 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001237 return err;
1238}
1239
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001240static int new_settings(struct hci_dev *hdev, struct sock *skip)
1241{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001242 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001243
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001244 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1245 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001246}
1247
Johan Hedberg91a668b2014-07-09 13:28:26 +03001248int mgmt_new_settings(struct hci_dev *hdev)
1249{
1250 return new_settings(hdev, NULL);
1251}
1252
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001253struct cmd_lookup {
1254 struct sock *sk;
1255 struct hci_dev *hdev;
1256 u8 mgmt_status;
1257};
1258
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001259static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001260{
1261 struct cmd_lookup *match = data;
1262
1263 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1264
1265 list_del(&cmd->list);
1266
1267 if (match->sk == NULL) {
1268 match->sk = cmd->sk;
1269 sock_hold(match->sk);
1270 }
1271
1272 mgmt_pending_free(cmd);
1273}
1274
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001275static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001276{
1277 u8 *status = data;
1278
Johan Hedberga69e8372015-03-06 21:08:53 +02001279 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001280 mgmt_pending_remove(cmd);
1281}
1282
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001283static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001284{
1285 if (cmd->cmd_complete) {
1286 u8 *status = data;
1287
1288 cmd->cmd_complete(cmd, *status);
1289 mgmt_pending_remove(cmd);
1290
1291 return;
1292 }
1293
1294 cmd_status_rsp(cmd, data);
1295}
1296
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001297static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001298{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001299 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1300 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001301}
1302
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001303static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001304{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001305 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1306 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001307}
1308
Johan Hedberge6fe7982013-10-02 15:45:22 +03001309static u8 mgmt_bredr_support(struct hci_dev *hdev)
1310{
1311 if (!lmp_bredr_capable(hdev))
1312 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001313 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001314 return MGMT_STATUS_REJECTED;
1315 else
1316 return MGMT_STATUS_SUCCESS;
1317}
1318
1319static u8 mgmt_le_support(struct hci_dev *hdev)
1320{
1321 if (!lmp_le_capable(hdev))
1322 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001323 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001324 return MGMT_STATUS_REJECTED;
1325 else
1326 return MGMT_STATUS_SUCCESS;
1327}
1328
Johan Hedbergaed1a882015-11-22 17:24:44 +03001329void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001330{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001331 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001332
Marcel Holtmann181d6952020-05-06 09:57:47 +02001333 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001334
1335 hci_dev_lock(hdev);
1336
Johan Hedberg333ae952015-03-17 13:48:47 +02001337 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001338 if (!cmd)
1339 goto unlock;
1340
1341 if (status) {
1342 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001343 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001344 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001345 goto remove_cmd;
1346 }
1347
Johan Hedbergaed1a882015-11-22 17:24:44 +03001348 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1349 hdev->discov_timeout > 0) {
1350 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1351 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001352 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001353
1354 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001355 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001356
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001357remove_cmd:
1358 mgmt_pending_remove(cmd);
1359
1360unlock:
1361 hci_dev_unlock(hdev);
1362}
1363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001364static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001365 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001367 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001368 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001369 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001370 int err;
1371
Marcel Holtmann181d6952020-05-06 09:57:47 +02001372 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001373
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001374 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1375 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1377 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001378
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001379 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001380 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001382
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001383 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001384
1385 /* Disabling discoverable requires that no timeout is set,
1386 * and enabling limited discoverable requires a timeout.
1387 */
1388 if ((cp->val == 0x00 && timeout > 0) ||
1389 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001390 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1391 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001392
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001393 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001394
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001395 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001396 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1397 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001398 goto failed;
1399 }
1400
Johan Hedberg333ae952015-03-17 13:48:47 +02001401 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1402 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001403 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1404 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001405 goto failed;
1406 }
1407
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001408 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001409 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1410 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001411 goto failed;
1412 }
1413
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001414 if (hdev->advertising_paused) {
1415 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1416 MGMT_STATUS_BUSY);
1417 goto failed;
1418 }
1419
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001420 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001421 bool changed = false;
1422
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001423 /* Setting limited discoverable when powered off is
1424 * not a valid operation since it requires a timeout
1425 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1426 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001427 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001428 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001429 changed = true;
1430 }
1431
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001432 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001433 if (err < 0)
1434 goto failed;
1435
1436 if (changed)
1437 err = new_settings(hdev, sk);
1438
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001439 goto failed;
1440 }
1441
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001442 /* If the current mode is the same, then just update the timeout
1443 * value with the new value. And if only the timeout gets updated,
1444 * then no need for any HCI transactions.
1445 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001446 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1447 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1448 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001449 cancel_delayed_work(&hdev->discov_off);
1450 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001451
Marcel Holtmann36261542013-10-15 08:28:51 -07001452 if (cp->val && hdev->discov_timeout > 0) {
1453 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001454 queue_delayed_work(hdev->req_workqueue,
1455 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001456 }
1457
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001458 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001459 goto failed;
1460 }
1461
1462 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1463 if (!cmd) {
1464 err = -ENOMEM;
1465 goto failed;
1466 }
1467
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001468 /* Cancel any potential discoverable timeout that might be
1469 * still active and store new timeout value. The arming of
1470 * the timeout happens in the complete handler.
1471 */
1472 cancel_delayed_work(&hdev->discov_off);
1473 hdev->discov_timeout = timeout;
1474
Johan Hedbergaed1a882015-11-22 17:24:44 +03001475 if (cp->val)
1476 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1477 else
1478 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1479
Johan Hedbergb456f872013-10-19 23:38:22 +03001480 /* Limited discoverable mode */
1481 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001482 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001483 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001484 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001485
Johan Hedbergaed1a882015-11-22 17:24:44 +03001486 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1487 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001488
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001489failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001490 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001491 return err;
1492}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001493
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001494void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001495{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001496 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001497
Marcel Holtmann181d6952020-05-06 09:57:47 +02001498 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001499
1500 hci_dev_lock(hdev);
1501
Johan Hedberg333ae952015-03-17 13:48:47 +02001502 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001503 if (!cmd)
1504 goto unlock;
1505
Johan Hedberg37438c12013-10-14 16:20:05 +03001506 if (status) {
1507 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001508 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001509 goto remove_cmd;
1510 }
1511
Johan Hedberg2b76f452013-03-15 17:07:04 -05001512 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001513 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001514
Johan Hedberg37438c12013-10-14 16:20:05 +03001515remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001516 mgmt_pending_remove(cmd);
1517
1518unlock:
1519 hci_dev_unlock(hdev);
1520}
1521
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001522static int set_connectable_update_settings(struct hci_dev *hdev,
1523 struct sock *sk, u8 val)
1524{
1525 bool changed = false;
1526 int err;
1527
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001528 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001529 changed = true;
1530
1531 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001532 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001533 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001534 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1535 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001536 }
1537
1538 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1539 if (err < 0)
1540 return err;
1541
Johan Hedberg562064e2014-07-08 16:35:34 +03001542 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001543 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001544 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001545 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001546 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001547
1548 return 0;
1549}
1550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001551static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001552 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001554 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001555 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001556 int err;
1557
Marcel Holtmann181d6952020-05-06 09:57:47 +02001558 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001559
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001560 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1561 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001562 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1563 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001564
Johan Hedberga7e80f22013-01-09 16:05:19 +02001565 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001568
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001569 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001570
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001571 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001572 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001573 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001574 }
1575
Johan Hedberg333ae952015-03-17 13:48:47 +02001576 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1577 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001578 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1579 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001580 goto failed;
1581 }
1582
Johan Hedberg73f22f62010-12-29 16:00:25 +02001583 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1584 if (!cmd) {
1585 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001586 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001587 }
1588
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001589 if (cp->val) {
1590 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1591 } else {
1592 if (hdev->discov_timeout > 0)
1593 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001594
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001595 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1596 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1597 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001598 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001599
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001600 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1601 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001602
1603failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001604 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001605 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001606}
1607
Johan Hedbergb2939472014-07-30 09:22:23 +03001608static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001609 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001610{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001611 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001612 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001613 int err;
1614
Marcel Holtmann181d6952020-05-06 09:57:47 +02001615 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001616
Johan Hedberga7e80f22013-01-09 16:05:19 +02001617 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001618 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1619 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001620
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001622
1623 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001624 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001625 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001626 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001627
Johan Hedbergb2939472014-07-30 09:22:23 +03001628 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001629 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001630 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001631
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001632 if (changed) {
1633 /* In limited privacy mode the change of bondable mode
1634 * may affect the local advertising address.
1635 */
1636 if (hdev_is_powered(hdev) &&
1637 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1638 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1639 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1640 queue_work(hdev->req_workqueue,
1641 &hdev->discoverable_update);
1642
Marcel Holtmann55594352013-10-06 16:11:57 -07001643 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001644 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001645
Marcel Holtmann55594352013-10-06 16:11:57 -07001646unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001647 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001648 return err;
1649}
1650
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001651static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1652 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001653{
1654 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001655 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001656 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001657 int err;
1658
Marcel Holtmann181d6952020-05-06 09:57:47 +02001659 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001660
Johan Hedberge6fe7982013-10-02 15:45:22 +03001661 status = mgmt_bredr_support(hdev);
1662 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001663 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1664 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001665
Johan Hedberga7e80f22013-01-09 16:05:19 +02001666 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001667 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1668 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001669
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001670 hci_dev_lock(hdev);
1671
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001672 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001673 bool changed = false;
1674
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001675 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001676 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001677 changed = true;
1678 }
1679
1680 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1681 if (err < 0)
1682 goto failed;
1683
1684 if (changed)
1685 err = new_settings(hdev, sk);
1686
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001687 goto failed;
1688 }
1689
Johan Hedberg333ae952015-03-17 13:48:47 +02001690 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001691 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1692 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001693 goto failed;
1694 }
1695
1696 val = !!cp->val;
1697
1698 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1699 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1700 goto failed;
1701 }
1702
1703 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1704 if (!cmd) {
1705 err = -ENOMEM;
1706 goto failed;
1707 }
1708
1709 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1710 if (err < 0) {
1711 mgmt_pending_remove(cmd);
1712 goto failed;
1713 }
1714
1715failed:
1716 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001717 return err;
1718}
1719
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001720static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001721{
1722 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001723 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001724 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001725 int err;
1726
Marcel Holtmann181d6952020-05-06 09:57:47 +02001727 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001728
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001729 status = mgmt_bredr_support(hdev);
1730 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001732
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001733 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1735 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001736
Johan Hedberga7e80f22013-01-09 16:05:19 +02001737 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1739 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001740
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001741 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001742
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001743 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001744 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001745
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001746 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001747 changed = !hci_dev_test_and_set_flag(hdev,
1748 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001749 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001750 changed = hci_dev_test_and_clear_flag(hdev,
1751 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001752 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001753 changed = hci_dev_test_and_clear_flag(hdev,
1754 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001755 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001756 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001757 }
1758
1759 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1760 if (err < 0)
1761 goto failed;
1762
1763 if (changed)
1764 err = new_settings(hdev, sk);
1765
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001766 goto failed;
1767 }
1768
Johan Hedberg333ae952015-03-17 13:48:47 +02001769 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001770 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1771 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001772 goto failed;
1773 }
1774
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001775 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001776 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1777 goto failed;
1778 }
1779
1780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1781 if (!cmd) {
1782 err = -ENOMEM;
1783 goto failed;
1784 }
1785
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001786 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001787 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1788 sizeof(cp->val), &cp->val);
1789
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001790 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001791 if (err < 0) {
1792 mgmt_pending_remove(cmd);
1793 goto failed;
1794 }
1795
1796failed:
1797 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001798 return err;
1799}
1800
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001801static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001802{
1803 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001804 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001805 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001806 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001807
Marcel Holtmann181d6952020-05-06 09:57:47 +02001808 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001809
Johan Hedberge6fe7982013-10-02 15:45:22 +03001810 status = mgmt_bredr_support(hdev);
1811 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001812 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001813
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001814 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1816 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001817
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001818 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001819 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1820 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001821
Johan Hedberga7e80f22013-01-09 16:05:19 +02001822 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001823 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1824 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001825
Marcel Holtmannee392692013-10-01 22:59:23 -07001826 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001827
Johan Hedberg333ae952015-03-17 13:48:47 +02001828 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001829 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1830 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001831 goto unlock;
1832 }
1833
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001834 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001835 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001836 } else {
1837 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001838 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1839 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001840 goto unlock;
1841 }
1842
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001843 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001844 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001845
1846 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1847 if (err < 0)
1848 goto unlock;
1849
1850 if (changed)
1851 err = new_settings(hdev, sk);
1852
1853unlock:
1854 hci_dev_unlock(hdev);
1855 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001856}
1857
Marcel Holtmann1904a852015-01-11 13:50:44 -08001858static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001859{
1860 struct cmd_lookup match = { NULL, hdev };
1861
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301862 hci_dev_lock(hdev);
1863
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001864 if (status) {
1865 u8 mgmt_err = mgmt_status(status);
1866
1867 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1868 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301869 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001870 }
1871
1872 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1873
1874 new_settings(hdev, match.sk);
1875
1876 if (match.sk)
1877 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001878
1879 /* Make sure the controller has a good default for
1880 * advertising data. Restrict the update to when LE
1881 * has actually been enabled. During power on, the
1882 * update in powered_update_hci will take care of it.
1883 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001884 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001885 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001886 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301887 if (ext_adv_capable(hdev)) {
1888 int err;
1889
1890 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1891 if (!err)
1892 __hci_req_update_scan_rsp_data(&req, 0x00);
1893 } else {
1894 __hci_req_update_adv_data(&req, 0x00);
1895 __hci_req_update_scan_rsp_data(&req, 0x00);
1896 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001897 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001898 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001899 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301900
1901unlock:
1902 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001903}
1904
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906{
1907 struct mgmt_mode *cp = data;
1908 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001909 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001910 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001911 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001912 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001913
Marcel Holtmann181d6952020-05-06 09:57:47 +02001914 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001915
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001916 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001917 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1918 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001919
Johan Hedberga7e80f22013-01-09 16:05:19 +02001920 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001921 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1922 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001923
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001924 /* Bluetooth single mode LE only controllers or dual-mode
1925 * controllers configured as LE only devices, do not allow
1926 * switching LE off. These have either LE enabled explicitly
1927 * or BR/EDR has been previously switched off.
1928 *
1929 * When trying to enable an already enabled LE, then gracefully
1930 * send a positive response. Trying to disable it however will
1931 * result into rejection.
1932 */
1933 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1934 if (cp->val == 0x01)
1935 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1936
Johan Hedberga69e8372015-03-06 21:08:53 +02001937 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1938 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001939 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001940
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001941 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001942
1943 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001944 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001945
Florian Grandel847818d2015-06-18 03:16:46 +02001946 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001947 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001948
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001949 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950 bool changed = false;
1951
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001952 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001953 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001954 changed = true;
1955 }
1956
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001957 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001958 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001959 changed = true;
1960 }
1961
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1963 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001964 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001965
1966 if (changed)
1967 err = new_settings(hdev, sk);
1968
Johan Hedberg1de028c2012-02-29 19:55:35 -08001969 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970 }
1971
Johan Hedberg333ae952015-03-17 13:48:47 +02001972 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1973 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001974 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1975 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001976 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001977 }
1978
1979 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1980 if (!cmd) {
1981 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001982 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001983 }
1984
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001985 hci_req_init(&req, hdev);
1986
Johan Hedberg06199cf2012-02-22 16:37:11 +02001987 memset(&hci_cp, 0, sizeof(hci_cp));
1988
1989 if (val) {
1990 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001991 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001992 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001993 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001994 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301995
1996 if (ext_adv_capable(hdev))
1997 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001998 }
1999
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002000 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2001 &hci_cp);
2002
2003 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302004 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002005 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002006
Johan Hedberg1de028c2012-02-29 19:55:35 -08002007unlock:
2008 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002009 return err;
2010}
2011
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002012/* This is a helper function to test for pending mgmt commands that can
2013 * cause CoD or EIR HCI commands. We can only allow one such pending
2014 * mgmt command at a time since otherwise we cannot easily track what
2015 * the current values are, will be, and based on that calculate if a new
2016 * HCI command needs to be sent and if yes with what value.
2017 */
2018static bool pending_eir_or_class(struct hci_dev *hdev)
2019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002020 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002021
2022 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2023 switch (cmd->opcode) {
2024 case MGMT_OP_ADD_UUID:
2025 case MGMT_OP_REMOVE_UUID:
2026 case MGMT_OP_SET_DEV_CLASS:
2027 case MGMT_OP_SET_POWERED:
2028 return true;
2029 }
2030 }
2031
2032 return false;
2033}
2034
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002035static const u8 bluetooth_base_uuid[] = {
2036 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2037 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2038};
2039
2040static u8 get_uuid_size(const u8 *uuid)
2041{
2042 u32 val;
2043
2044 if (memcmp(uuid, bluetooth_base_uuid, 12))
2045 return 128;
2046
2047 val = get_unaligned_le32(&uuid[12]);
2048 if (val > 0xffff)
2049 return 32;
2050
2051 return 16;
2052}
2053
Johan Hedberg92da6092013-03-15 17:06:55 -05002054static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2055{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002056 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002057
2058 hci_dev_lock(hdev);
2059
Johan Hedberg333ae952015-03-17 13:48:47 +02002060 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002061 if (!cmd)
2062 goto unlock;
2063
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002064 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2065 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002066
2067 mgmt_pending_remove(cmd);
2068
2069unlock:
2070 hci_dev_unlock(hdev);
2071}
2072
Marcel Holtmann1904a852015-01-11 13:50:44 -08002073static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002074{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002075 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002076
2077 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2078}
2079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002081{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002082 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002083 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002084 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002086 int err;
2087
Marcel Holtmann181d6952020-05-06 09:57:47 +02002088 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002090 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002091
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002092 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002093 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2094 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002095 goto failed;
2096 }
2097
Andre Guedes92c4c202012-06-07 19:05:44 -03002098 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 if (!uuid) {
2100 err = -ENOMEM;
2101 goto failed;
2102 }
2103
2104 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002105 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002106 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002107
Johan Hedbergde66aa62013-01-27 00:31:27 +02002108 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002109
Johan Hedberg890ea892013-03-15 17:06:52 -05002110 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002111
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002112 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002113 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002114
Johan Hedberg92da6092013-03-15 17:06:55 -05002115 err = hci_req_run(&req, add_uuid_complete);
2116 if (err < 0) {
2117 if (err != -ENODATA)
2118 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002119
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002120 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2121 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002122 goto failed;
2123 }
2124
2125 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002126 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002127 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002128 goto failed;
2129 }
2130
2131 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002132
2133failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002134 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002135 return err;
2136}
2137
Johan Hedberg24b78d02012-02-23 23:24:30 +02002138static bool enable_service_cache(struct hci_dev *hdev)
2139{
2140 if (!hdev_is_powered(hdev))
2141 return false;
2142
Marcel Holtmann238be782015-03-13 02:11:06 -07002143 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002144 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2145 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146 return true;
2147 }
2148
2149 return false;
2150}
2151
Marcel Holtmann1904a852015-01-11 13:50:44 -08002152static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002153{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002154 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002155
2156 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2157}
2158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002160 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002161{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002162 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002163 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002164 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002165 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 -05002166 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002167 int err, found;
2168
Marcel Holtmann181d6952020-05-06 09:57:47 +02002169 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002171 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002172
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002173 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002174 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2175 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002176 goto unlock;
2177 }
2178
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002179 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002180 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002181
Johan Hedberg24b78d02012-02-23 23:24:30 +02002182 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002183 err = mgmt_cmd_complete(sk, hdev->id,
2184 MGMT_OP_REMOVE_UUID,
2185 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002186 goto unlock;
2187 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002188
Johan Hedberg9246a862012-02-23 21:33:16 +02002189 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002190 }
2191
2192 found = 0;
2193
Johan Hedberg056341c2013-01-27 00:31:30 +02002194 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002195 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2196 continue;
2197
2198 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002199 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002200 found++;
2201 }
2202
2203 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002204 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2205 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002206 goto unlock;
2207 }
2208
Johan Hedberg9246a862012-02-23 21:33:16 +02002209update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002210 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002211
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002212 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002213 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002214
Johan Hedberg92da6092013-03-15 17:06:55 -05002215 err = hci_req_run(&req, remove_uuid_complete);
2216 if (err < 0) {
2217 if (err != -ENODATA)
2218 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002219
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002220 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2221 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002222 goto unlock;
2223 }
2224
2225 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002226 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002227 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002228 goto unlock;
2229 }
2230
2231 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002232
2233unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002234 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002235 return err;
2236}
2237
Marcel Holtmann1904a852015-01-11 13:50:44 -08002238static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002239{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002240 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002241
2242 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2243}
2244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002246 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002247{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002248 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002249 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002250 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002251 int err;
2252
Marcel Holtmann181d6952020-05-06 09:57:47 +02002253 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002254
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002255 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002256 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2257 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002258
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002259 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002260
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002261 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002262 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2263 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002264 goto unlock;
2265 }
2266
2267 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002268 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2269 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002270 goto unlock;
2271 }
2272
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002273 hdev->major_class = cp->major;
2274 hdev->minor_class = cp->minor;
2275
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002276 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002277 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2278 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002279 goto unlock;
2280 }
2281
Johan Hedberg890ea892013-03-15 17:06:52 -05002282 hci_req_init(&req, hdev);
2283
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002284 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002285 hci_dev_unlock(hdev);
2286 cancel_delayed_work_sync(&hdev->service_cache);
2287 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002288 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002289 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002290
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002291 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002292
Johan Hedberg92da6092013-03-15 17:06:55 -05002293 err = hci_req_run(&req, set_class_complete);
2294 if (err < 0) {
2295 if (err != -ENODATA)
2296 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002297
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002298 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2299 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002300 goto unlock;
2301 }
2302
2303 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002304 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002305 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002306 goto unlock;
2307 }
2308
2309 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002310
Johan Hedbergb5235a62012-02-21 14:32:24 +02002311unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002312 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002313 return err;
2314}
2315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002317 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002318{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002319 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002320 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2321 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002322 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002323 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002324 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002325
Marcel Holtmann181d6952020-05-06 09:57:47 +02002326 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002327
2328 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002329 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2330 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002331
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002332 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002333 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002334 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2335 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002336 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002338 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002339
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002340 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002341 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002342 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2343 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002344 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2345 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346 }
2347
Johan Hedberg4ae14302013-01-20 14:27:13 +02002348 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002349 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2350 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002351
Marcel Holtmann181d6952020-05-06 09:57:47 +02002352 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2353 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002354
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002355 for (i = 0; i < key_count; i++) {
2356 struct mgmt_link_key_info *key = &cp->keys[i];
2357
Marcel Holtmann8e991132014-01-10 02:07:25 -08002358 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002359 return mgmt_cmd_status(sk, hdev->id,
2360 MGMT_OP_LOAD_LINK_KEYS,
2361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002362 }
2363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002364 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002365
2366 hci_link_keys_clear(hdev);
2367
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002368 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002369 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002370 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002371 changed = hci_dev_test_and_clear_flag(hdev,
2372 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002373
2374 if (changed)
2375 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002377 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002378 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002379
Alain Michaud600a8742020-01-07 00:43:17 +00002380 if (hci_is_blocked_key(hdev,
2381 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2382 key->val)) {
2383 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2384 &key->addr.bdaddr);
2385 continue;
2386 }
2387
Johan Hedberg58e92932014-06-24 14:00:26 +03002388 /* Always ignore debug keys and require a new pairing if
2389 * the user wants to use them.
2390 */
2391 if (key->type == HCI_LK_DEBUG_COMBINATION)
2392 continue;
2393
Johan Hedberg7652ff62014-06-24 13:15:49 +03002394 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2395 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002396 }
2397
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002398 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002400 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002401
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002402 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002403}
2404
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002405static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002407{
2408 struct mgmt_ev_device_unpaired ev;
2409
2410 bacpy(&ev.addr.bdaddr, bdaddr);
2411 ev.addr.type = addr_type;
2412
2413 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002414 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002415}
2416
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002417static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002418 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002419{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002420 struct mgmt_cp_unpair_device *cp = data;
2421 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002422 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002423 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002424 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002425 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002426 int err;
2427
Johan Hedberga8a1d192011-11-10 15:54:38 +02002428 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002429 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2430 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002431
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002432 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002433 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2434 MGMT_STATUS_INVALID_PARAMS,
2435 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002436
Johan Hedberg118da702013-01-20 14:27:20 +02002437 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002438 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2439 MGMT_STATUS_INVALID_PARAMS,
2440 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002441
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002442 hci_dev_lock(hdev);
2443
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002444 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002445 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2446 MGMT_STATUS_NOT_POWERED, &rp,
2447 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002448 goto unlock;
2449 }
2450
Johan Hedberge0b2b272014-02-18 17:14:31 +02002451 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002452 /* If disconnection is requested, then look up the
2453 * connection. If the remote device is connected, it
2454 * will be later used to terminate the link.
2455 *
2456 * Setting it to NULL explicitly will cause no
2457 * termination of the link.
2458 */
2459 if (cp->disconnect)
2460 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2461 &cp->addr.bdaddr);
2462 else
2463 conn = NULL;
2464
Johan Hedberg124f6e32012-02-09 13:50:12 +02002465 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002466 if (err < 0) {
2467 err = mgmt_cmd_complete(sk, hdev->id,
2468 MGMT_OP_UNPAIR_DEVICE,
2469 MGMT_STATUS_NOT_PAIRED, &rp,
2470 sizeof(rp));
2471 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002472 }
2473
Johan Hedbergec182f02015-10-21 18:03:03 +03002474 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002475 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002476
Johan Hedbergec182f02015-10-21 18:03:03 +03002477 /* LE address type */
2478 addr_type = le_addr_type(cp->addr.type);
2479
Matias Karhumaacb28c302018-09-26 09:13:46 +03002480 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2481 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002482 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002483 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2484 MGMT_STATUS_NOT_PAIRED, &rp,
2485 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002486 goto unlock;
2487 }
2488
Johan Hedbergec182f02015-10-21 18:03:03 +03002489 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2490 if (!conn) {
2491 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2492 goto done;
2493 }
2494
Johan Hedbergc81d5552015-10-22 09:38:35 +03002495
Johan Hedbergec182f02015-10-21 18:03:03 +03002496 /* Defer clearing up the connection parameters until closing to
2497 * give a chance of keeping them if a repairing happens.
2498 */
2499 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2500
Johan Hedbergfc643612015-10-22 09:38:31 +03002501 /* Disable auto-connection parameters if present */
2502 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2503 if (params) {
2504 if (params->explicit_connect)
2505 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2506 else
2507 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2508 }
2509
Johan Hedbergec182f02015-10-21 18:03:03 +03002510 /* If disconnection is not requested, then clear the connection
2511 * variable so that the link is not terminated.
2512 */
2513 if (!cp->disconnect)
2514 conn = NULL;
2515
2516done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002517 /* If the connection variable is set, then termination of the
2518 * link is requested.
2519 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002520 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002521 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2522 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002523 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002524 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002525 }
2526
Johan Hedberg124f6e32012-02-09 13:50:12 +02002527 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002529 if (!cmd) {
2530 err = -ENOMEM;
2531 goto unlock;
2532 }
2533
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002534 cmd->cmd_complete = addr_cmd_complete;
2535
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002536 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002537 if (err < 0)
2538 mgmt_pending_remove(cmd);
2539
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002540unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002541 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002542 return err;
2543}
2544
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002547{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002548 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002549 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002550 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002551 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002552 int err;
2553
Marcel Holtmann181d6952020-05-06 09:57:47 +02002554 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555
Johan Hedberg06a63b12013-01-20 14:27:21 +02002556 memset(&rp, 0, sizeof(rp));
2557 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2558 rp.addr.type = cp->addr.type;
2559
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002560 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002561 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2562 MGMT_STATUS_INVALID_PARAMS,
2563 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002565 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002566
2567 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2569 MGMT_STATUS_NOT_POWERED, &rp,
2570 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002571 goto failed;
2572 }
2573
Johan Hedberg333ae952015-03-17 13:48:47 +02002574 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2576 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002577 goto failed;
2578 }
2579
Andre Guedes591f47f2012-04-24 21:02:49 -03002580 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002581 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2582 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002583 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002584 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2585 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002586
Vishal Agarwalf9607272012-06-13 05:32:43 +05302587 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002588 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2589 MGMT_STATUS_NOT_CONNECTED, &rp,
2590 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591 goto failed;
2592 }
2593
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002594 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002595 if (!cmd) {
2596 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002597 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002598 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002599
Johan Hedbergf5818c22014-12-05 13:36:02 +02002600 cmd->cmd_complete = generic_cmd_complete;
2601
Johan Hedberge3f2f922014-08-18 20:33:33 +03002602 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002603 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002604 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002605
2606failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002607 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002608 return err;
2609}
2610
Andre Guedes57c14772012-04-24 21:02:50 -03002611static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002612{
2613 switch (link_type) {
2614 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002615 switch (addr_type) {
2616 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002617 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002618
Johan Hedberg48264f02011-11-09 13:58:58 +02002619 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002620 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002621 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002622 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002623
Johan Hedberg4c659c32011-11-07 23:13:39 +02002624 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002625 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002626 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002627 }
2628}
2629
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2631 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002632{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002633 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002634 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002635 int err;
2636 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002637
Marcel Holtmann181d6952020-05-06 09:57:47 +02002638 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002641
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002643 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2644 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002645 goto unlock;
2646 }
2647
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002648 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002649 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2650 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002651 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002652 }
2653
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002654 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002655 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002656 err = -ENOMEM;
2657 goto unlock;
2658 }
2659
Johan Hedberg2784eb42011-01-21 13:56:35 +02002660 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002661 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002662 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2663 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002664 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002665 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002666 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002667 continue;
2668 i++;
2669 }
2670
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002671 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002672
Johan Hedberg4c659c32011-11-07 23:13:39 +02002673 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002674 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002675 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002676
Johan Hedberga38528f2011-01-22 06:46:43 +02002677 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002678
2679unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002680 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002681 return err;
2682}
2683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002684static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002686{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002687 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002688 int err;
2689
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002690 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002691 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002692 if (!cmd)
2693 return -ENOMEM;
2694
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002695 cmd->cmd_complete = addr_cmd_complete;
2696
Johan Hedbergd8457692012-02-17 14:24:57 +02002697 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002699 if (err < 0)
2700 mgmt_pending_remove(cmd);
2701
2702 return err;
2703}
2704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002707{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002708 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002710 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002711 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002712 int err;
2713
Marcel Holtmann181d6952020-05-06 09:57:47 +02002714 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002716 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002718 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002719 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2720 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002721 goto failed;
2722 }
2723
Johan Hedbergd8457692012-02-17 14:24:57 +02002724 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002725 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002726 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2727 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002728 goto failed;
2729 }
2730
2731 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002732 struct mgmt_cp_pin_code_neg_reply ncp;
2733
2734 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002735
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002736 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002739 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002740 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2741 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002742
2743 goto failed;
2744 }
2745
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002746 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002747 if (!cmd) {
2748 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002749 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002750 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002751
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002752 cmd->cmd_complete = addr_cmd_complete;
2753
Johan Hedbergd8457692012-02-17 14:24:57 +02002754 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002755 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002756 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002757
2758 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2759 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002760 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002761
2762failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002764 return err;
2765}
2766
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2768 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002769{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002770 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002771
Marcel Holtmann181d6952020-05-06 09:57:47 +02002772 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002773
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002774 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002775 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2776 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002778 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002779
2780 hdev->io_capability = cp->io_capability;
2781
Marcel Holtmann181d6952020-05-06 09:57:47 +02002782 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002784 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002785
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002786 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2787 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002788}
2789
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002790static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791{
2792 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002793 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002794
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002795 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002796 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2797 continue;
2798
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799 if (cmd->user_data != conn)
2800 continue;
2801
2802 return cmd;
2803 }
2804
2805 return NULL;
2806}
2807
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002808static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002809{
2810 struct mgmt_rp_pair_device rp;
2811 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002812 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002813
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002814 bacpy(&rp.addr.bdaddr, &conn->dst);
2815 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002816
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002817 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2818 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819
2820 /* So we don't get further callbacks for this connection */
2821 conn->connect_cfm_cb = NULL;
2822 conn->security_cfm_cb = NULL;
2823 conn->disconn_cfm_cb = NULL;
2824
David Herrmann76a68ba2013-04-06 20:28:37 +02002825 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002826
2827 /* The device is paired so there is no need to remove
2828 * its connection parameters anymore.
2829 */
2830 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002831
2832 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002833
2834 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002835}
2836
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002837void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2838{
2839 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002840 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002841
2842 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002843 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002844 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002845 mgmt_pending_remove(cmd);
2846 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002847}
2848
Johan Hedberge9a416b2011-02-19 12:05:56 -03002849static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2850{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002851 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002852
2853 BT_DBG("status %u", status);
2854
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002855 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002856 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002857 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002858 return;
2859 }
2860
2861 cmd->cmd_complete(cmd, mgmt_status(status));
2862 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002863}
2864
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002865static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302866{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002867 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302868
2869 BT_DBG("status %u", status);
2870
2871 if (!status)
2872 return;
2873
2874 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002875 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302876 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002877 return;
2878 }
2879
2880 cmd->cmd_complete(cmd, mgmt_status(status));
2881 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302882}
2883
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002884static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002885 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002886{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002887 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002888 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002889 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002890 u8 sec_level, auth_type;
2891 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002892 int err;
2893
Marcel Holtmann181d6952020-05-06 09:57:47 +02002894 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002895
Szymon Jancf950a30e2013-01-18 12:48:07 +01002896 memset(&rp, 0, sizeof(rp));
2897 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2898 rp.addr.type = cp->addr.type;
2899
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002900 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002901 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2902 MGMT_STATUS_INVALID_PARAMS,
2903 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002904
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002905 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002906 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2907 MGMT_STATUS_INVALID_PARAMS,
2908 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002909
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002910 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002911
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002912 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002913 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2914 MGMT_STATUS_NOT_POWERED, &rp,
2915 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002916 goto unlock;
2917 }
2918
Johan Hedberg55e76b32015-03-10 22:34:40 +02002919 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2920 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2921 MGMT_STATUS_ALREADY_PAIRED, &rp,
2922 sizeof(rp));
2923 goto unlock;
2924 }
2925
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002926 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002927 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002928
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002929 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002930 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2931 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002932 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002933 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002934 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002935
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002936 /* When pairing a new device, it is expected to remember
2937 * this device for future connections. Adding the connection
2938 * parameter information ahead of time allows tracking
2939 * of the slave preferred values and will speed up any
2940 * further connection establishment.
2941 *
2942 * If connection parameters already exist, then they
2943 * will be kept and this function does nothing.
2944 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002945 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2946
2947 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2948 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002949
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002950 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2951 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002952 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002953 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002954
Ville Tervo30e76272011-02-22 16:10:53 -03002955 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002956 int status;
2957
2958 if (PTR_ERR(conn) == -EBUSY)
2959 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002960 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2961 status = MGMT_STATUS_NOT_SUPPORTED;
2962 else if (PTR_ERR(conn) == -ECONNREFUSED)
2963 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002964 else
2965 status = MGMT_STATUS_CONNECT_FAILED;
2966
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002967 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2968 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002969 goto unlock;
2970 }
2971
2972 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002973 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002974 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2975 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002976 goto unlock;
2977 }
2978
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002979 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002980 if (!cmd) {
2981 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002982 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002983 goto unlock;
2984 }
2985
Johan Hedberg04ab2742014-12-05 13:36:04 +02002986 cmd->cmd_complete = pairing_complete;
2987
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002988 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002989 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002990 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002991 conn->security_cfm_cb = pairing_complete_cb;
2992 conn->disconn_cfm_cb = pairing_complete_cb;
2993 } else {
2994 conn->connect_cfm_cb = le_pairing_complete_cb;
2995 conn->security_cfm_cb = le_pairing_complete_cb;
2996 conn->disconn_cfm_cb = le_pairing_complete_cb;
2997 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002998
Johan Hedberge9a416b2011-02-19 12:05:56 -03002999 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003000 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003001
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003002 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003003 hci_conn_security(conn, sec_level, auth_type, true)) {
3004 cmd->cmd_complete(cmd, 0);
3005 mgmt_pending_remove(cmd);
3006 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003007
3008 err = 0;
3009
3010unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003011 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003012 return err;
3013}
3014
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3016 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003017{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003018 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003019 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003020 struct hci_conn *conn;
3021 int err;
3022
Marcel Holtmann181d6952020-05-06 09:57:47 +02003023 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003024
Johan Hedberg28424702012-02-02 04:02:29 +02003025 hci_dev_lock(hdev);
3026
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003027 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003028 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3029 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003030 goto unlock;
3031 }
3032
Johan Hedberg333ae952015-03-17 13:48:47 +02003033 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003034 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003035 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003037 goto unlock;
3038 }
3039
3040 conn = cmd->user_data;
3041
3042 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003043 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3044 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003045 goto unlock;
3046 }
3047
Johan Hedberga511b352014-12-11 21:45:45 +02003048 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3049 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003050
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003051 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3052 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003053unlock:
3054 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003055 return err;
3056}
3057
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003058static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003059 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003061{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003062 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003063 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003064 int err;
3065
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003066 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003067
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003068 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003069 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3070 MGMT_STATUS_NOT_POWERED, addr,
3071 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003072 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003073 }
3074
Johan Hedberg1707c602013-03-15 17:07:15 -05003075 if (addr->type == BDADDR_BREDR)
3076 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003077 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003078 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3079 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003080
Johan Hedberg272d90d2012-02-09 15:26:12 +02003081 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003082 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3083 MGMT_STATUS_NOT_CONNECTED, addr,
3084 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003085 goto done;
3086 }
3087
Johan Hedberg1707c602013-03-15 17:07:15 -05003088 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003089 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003090 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003091 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3092 MGMT_STATUS_SUCCESS, addr,
3093 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003094 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003095 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3096 MGMT_STATUS_FAILED, addr,
3097 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003098
Brian Gix47c15e22011-11-16 13:53:14 -08003099 goto done;
3100 }
3101
Johan Hedberg1707c602013-03-15 17:07:15 -05003102 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003103 if (!cmd) {
3104 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003105 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003106 }
3107
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003108 cmd->cmd_complete = addr_cmd_complete;
3109
Brian Gix0df4c182011-11-16 13:53:13 -08003110 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003111 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3112 struct hci_cp_user_passkey_reply cp;
3113
Johan Hedberg1707c602013-03-15 17:07:15 -05003114 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003115 cp.passkey = passkey;
3116 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3117 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003118 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3119 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003120
Johan Hedberga664b5b2011-02-19 12:06:02 -03003121 if (err < 0)
3122 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003123
Brian Gix0df4c182011-11-16 13:53:13 -08003124done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003125 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003126 return err;
3127}
3128
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303129static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3130 void *data, u16 len)
3131{
3132 struct mgmt_cp_pin_code_neg_reply *cp = data;
3133
Marcel Holtmann181d6952020-05-06 09:57:47 +02003134 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303135
Johan Hedberg1707c602013-03-15 17:07:15 -05003136 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303137 MGMT_OP_PIN_CODE_NEG_REPLY,
3138 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3139}
3140
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003141static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3142 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003144 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003145
Marcel Holtmann181d6952020-05-06 09:57:47 +02003146 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003147
3148 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003149 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3150 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003151
Johan Hedberg1707c602013-03-15 17:07:15 -05003152 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 MGMT_OP_USER_CONFIRM_REPLY,
3154 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003155}
3156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003157static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003159{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003160 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003161
Marcel Holtmann181d6952020-05-06 09:57:47 +02003162 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003163
Johan Hedberg1707c602013-03-15 17:07:15 -05003164 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3166 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003167}
3168
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3170 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003172 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003173
Marcel Holtmann181d6952020-05-06 09:57:47 +02003174 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003175
Johan Hedberg1707c602013-03-15 17:07:15 -05003176 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003177 MGMT_OP_USER_PASSKEY_REPLY,
3178 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003179}
3180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003182 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003183{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003184 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003185
Marcel Holtmann181d6952020-05-06 09:57:47 +02003186 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003187
Johan Hedberg1707c602013-03-15 17:07:15 -05003188 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3190 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003191}
3192
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003193static void adv_expire(struct hci_dev *hdev, u32 flags)
3194{
3195 struct adv_info *adv_instance;
3196 struct hci_request req;
3197 int err;
3198
3199 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3200 if (!adv_instance)
3201 return;
3202
3203 /* stop if current instance doesn't need to be changed */
3204 if (!(adv_instance->flags & flags))
3205 return;
3206
3207 cancel_adv_timeout(hdev);
3208
3209 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3210 if (!adv_instance)
3211 return;
3212
3213 hci_req_init(&req, hdev);
3214 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3215 true);
3216 if (err)
3217 return;
3218
3219 hci_req_run(&req, NULL);
3220}
3221
Marcel Holtmann1904a852015-01-11 13:50:44 -08003222static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003223{
3224 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003225 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003226
Marcel Holtmann181d6952020-05-06 09:57:47 +02003227 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003228
3229 hci_dev_lock(hdev);
3230
Johan Hedberg333ae952015-03-17 13:48:47 +02003231 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003232 if (!cmd)
3233 goto unlock;
3234
3235 cp = cmd->param;
3236
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003237 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003238 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3239 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003240 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003241 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3242 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003243
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003244 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3245 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3246 }
3247
Johan Hedberg13928972013-03-15 17:07:00 -05003248 mgmt_pending_remove(cmd);
3249
3250unlock:
3251 hci_dev_unlock(hdev);
3252}
3253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003254static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003255 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003256{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003257 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003258 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003259 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003260 int err;
3261
Marcel Holtmann181d6952020-05-06 09:57:47 +02003262 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003264 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003265
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003266 /* If the old values are the same as the new ones just return a
3267 * direct command complete event.
3268 */
3269 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3270 !memcmp(hdev->short_name, cp->short_name,
3271 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003272 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3273 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003274 goto failed;
3275 }
3276
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003277 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003278
Johan Hedbergb5235a62012-02-21 14:32:24 +02003279 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003280 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003281
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003282 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3283 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003284 if (err < 0)
3285 goto failed;
3286
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003287 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3288 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003289 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003290
Johan Hedbergb5235a62012-02-21 14:32:24 +02003291 goto failed;
3292 }
3293
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003294 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003295 if (!cmd) {
3296 err = -ENOMEM;
3297 goto failed;
3298 }
3299
Johan Hedberg13928972013-03-15 17:07:00 -05003300 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3301
Johan Hedberg890ea892013-03-15 17:06:52 -05003302 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003303
3304 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003305 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003306 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003307 }
3308
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003309 /* The name is stored in the scan response data and so
3310 * no need to udpate the advertising data here.
3311 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003312 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003313 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003314
Johan Hedberg13928972013-03-15 17:07:00 -05003315 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003316 if (err < 0)
3317 mgmt_pending_remove(cmd);
3318
3319failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003320 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003321 return err;
3322}
3323
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003324static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3325 u16 len)
3326{
3327 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003328 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003329 int err;
3330
Marcel Holtmann181d6952020-05-06 09:57:47 +02003331 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003332
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003333 if (!lmp_le_capable(hdev))
3334 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3335 MGMT_STATUS_NOT_SUPPORTED);
3336
Alain Michaud6613bab2020-01-22 19:47:44 +00003337 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003338
3339 hci_dev_lock(hdev);
3340
Alain Michaud6613bab2020-01-22 19:47:44 +00003341 if (hdev->appearance != appearance) {
3342 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003343
3344 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3345 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003346
3347 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003348 }
3349
3350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3351 0);
3352
3353 hci_dev_unlock(hdev);
3354
3355 return err;
3356}
3357
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303358static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3359 void *data, u16 len)
3360{
3361 struct mgmt_rp_get_phy_confguration rp;
3362
Marcel Holtmann181d6952020-05-06 09:57:47 +02003363 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303364
3365 hci_dev_lock(hdev);
3366
3367 memset(&rp, 0, sizeof(rp));
3368
3369 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3370 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3371 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3372
3373 hci_dev_unlock(hdev);
3374
3375 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3376 &rp, sizeof(rp));
3377}
3378
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303379int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3380{
3381 struct mgmt_ev_phy_configuration_changed ev;
3382
3383 memset(&ev, 0, sizeof(ev));
3384
3385 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3386
3387 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3388 sizeof(ev), skip);
3389}
3390
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303391static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3392 u16 opcode, struct sk_buff *skb)
3393{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303394 struct mgmt_pending_cmd *cmd;
3395
Marcel Holtmann181d6952020-05-06 09:57:47 +02003396 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303397
3398 hci_dev_lock(hdev);
3399
3400 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3401 if (!cmd)
3402 goto unlock;
3403
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303404 if (status) {
3405 mgmt_cmd_status(cmd->sk, hdev->id,
3406 MGMT_OP_SET_PHY_CONFIGURATION,
3407 mgmt_status(status));
3408 } else {
3409 mgmt_cmd_complete(cmd->sk, hdev->id,
3410 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3411 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303412
3413 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303414 }
3415
3416 mgmt_pending_remove(cmd);
3417
3418unlock:
3419 hci_dev_unlock(hdev);
3420}
3421
3422static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3423 void *data, u16 len)
3424{
3425 struct mgmt_cp_set_phy_confguration *cp = data;
3426 struct hci_cp_le_set_default_phy cp_phy;
3427 struct mgmt_pending_cmd *cmd;
3428 struct hci_request req;
3429 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3430 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303431 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303432 int err;
3433
Marcel Holtmann181d6952020-05-06 09:57:47 +02003434 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303435
3436 configurable_phys = get_configurable_phys(hdev);
3437 supported_phys = get_supported_phys(hdev);
3438 selected_phys = __le32_to_cpu(cp->selected_phys);
3439
3440 if (selected_phys & ~supported_phys)
3441 return mgmt_cmd_status(sk, hdev->id,
3442 MGMT_OP_SET_PHY_CONFIGURATION,
3443 MGMT_STATUS_INVALID_PARAMS);
3444
3445 unconfigure_phys = supported_phys & ~configurable_phys;
3446
3447 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3448 return mgmt_cmd_status(sk, hdev->id,
3449 MGMT_OP_SET_PHY_CONFIGURATION,
3450 MGMT_STATUS_INVALID_PARAMS);
3451
3452 if (selected_phys == get_selected_phys(hdev))
3453 return mgmt_cmd_complete(sk, hdev->id,
3454 MGMT_OP_SET_PHY_CONFIGURATION,
3455 0, NULL, 0);
3456
3457 hci_dev_lock(hdev);
3458
3459 if (!hdev_is_powered(hdev)) {
3460 err = mgmt_cmd_status(sk, hdev->id,
3461 MGMT_OP_SET_PHY_CONFIGURATION,
3462 MGMT_STATUS_REJECTED);
3463 goto unlock;
3464 }
3465
3466 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3467 err = mgmt_cmd_status(sk, hdev->id,
3468 MGMT_OP_SET_PHY_CONFIGURATION,
3469 MGMT_STATUS_BUSY);
3470 goto unlock;
3471 }
3472
3473 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3474 pkt_type |= (HCI_DH3 | HCI_DM3);
3475 else
3476 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3477
3478 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3479 pkt_type |= (HCI_DH5 | HCI_DM5);
3480 else
3481 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3482
3483 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3484 pkt_type &= ~HCI_2DH1;
3485 else
3486 pkt_type |= HCI_2DH1;
3487
3488 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3489 pkt_type &= ~HCI_2DH3;
3490 else
3491 pkt_type |= HCI_2DH3;
3492
3493 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3494 pkt_type &= ~HCI_2DH5;
3495 else
3496 pkt_type |= HCI_2DH5;
3497
3498 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3499 pkt_type &= ~HCI_3DH1;
3500 else
3501 pkt_type |= HCI_3DH1;
3502
3503 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3504 pkt_type &= ~HCI_3DH3;
3505 else
3506 pkt_type |= HCI_3DH3;
3507
3508 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3509 pkt_type &= ~HCI_3DH5;
3510 else
3511 pkt_type |= HCI_3DH5;
3512
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303513 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303514 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303515 changed = true;
3516 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303517
3518 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3519 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303520 if (changed)
3521 mgmt_phy_configuration_changed(hdev, sk);
3522
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303523 err = mgmt_cmd_complete(sk, hdev->id,
3524 MGMT_OP_SET_PHY_CONFIGURATION,
3525 0, NULL, 0);
3526
3527 goto unlock;
3528 }
3529
3530 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3531 len);
3532 if (!cmd) {
3533 err = -ENOMEM;
3534 goto unlock;
3535 }
3536
3537 hci_req_init(&req, hdev);
3538
3539 memset(&cp_phy, 0, sizeof(cp_phy));
3540
3541 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3542 cp_phy.all_phys |= 0x01;
3543
3544 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3545 cp_phy.all_phys |= 0x02;
3546
3547 if (selected_phys & MGMT_PHY_LE_1M_TX)
3548 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3549
3550 if (selected_phys & MGMT_PHY_LE_2M_TX)
3551 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3552
3553 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3554 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3555
3556 if (selected_phys & MGMT_PHY_LE_1M_RX)
3557 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3558
3559 if (selected_phys & MGMT_PHY_LE_2M_RX)
3560 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3561
3562 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3563 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3564
3565 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3566
3567 err = hci_req_run_skb(&req, set_default_phy_complete);
3568 if (err < 0)
3569 mgmt_pending_remove(cmd);
3570
3571unlock:
3572 hci_dev_unlock(hdev);
3573
3574 return err;
3575}
3576
Alain Michaud600a8742020-01-07 00:43:17 +00003577static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3578 u16 len)
3579{
3580 int err = MGMT_STATUS_SUCCESS;
3581 struct mgmt_cp_set_blocked_keys *keys = data;
3582 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3583 sizeof(struct mgmt_blocked_key_info));
3584 u16 key_count, expected_len;
3585 int i;
3586
Marcel Holtmann181d6952020-05-06 09:57:47 +02003587 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003588
3589 key_count = __le16_to_cpu(keys->key_count);
3590 if (key_count > max_key_count) {
3591 bt_dev_err(hdev, "too big key_count value %u", key_count);
3592 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3593 MGMT_STATUS_INVALID_PARAMS);
3594 }
3595
3596 expected_len = struct_size(keys, keys, key_count);
3597 if (expected_len != len) {
3598 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3599 expected_len, len);
3600 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3601 MGMT_STATUS_INVALID_PARAMS);
3602 }
3603
3604 hci_dev_lock(hdev);
3605
3606 hci_blocked_keys_clear(hdev);
3607
3608 for (i = 0; i < keys->key_count; ++i) {
3609 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3610
3611 if (!b) {
3612 err = MGMT_STATUS_NO_RESOURCES;
3613 break;
3614 }
3615
3616 b->type = keys->keys[i].type;
3617 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3618 list_add_rcu(&b->list, &hdev->blocked_keys);
3619 }
3620 hci_dev_unlock(hdev);
3621
3622 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3623 err, NULL, 0);
3624}
3625
Alain Michaud00bce3f2020-03-05 16:14:59 +00003626static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3627 void *data, u16 len)
3628{
3629 struct mgmt_mode *cp = data;
3630 int err;
3631 bool changed = false;
3632
Marcel Holtmann181d6952020-05-06 09:57:47 +02003633 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003634
3635 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3636 return mgmt_cmd_status(sk, hdev->id,
3637 MGMT_OP_SET_WIDEBAND_SPEECH,
3638 MGMT_STATUS_NOT_SUPPORTED);
3639
3640 if (cp->val != 0x00 && cp->val != 0x01)
3641 return mgmt_cmd_status(sk, hdev->id,
3642 MGMT_OP_SET_WIDEBAND_SPEECH,
3643 MGMT_STATUS_INVALID_PARAMS);
3644
3645 hci_dev_lock(hdev);
3646
3647 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3648 err = mgmt_cmd_status(sk, hdev->id,
3649 MGMT_OP_SET_WIDEBAND_SPEECH,
3650 MGMT_STATUS_BUSY);
3651 goto unlock;
3652 }
3653
3654 if (hdev_is_powered(hdev) &&
3655 !!cp->val != hci_dev_test_flag(hdev,
3656 HCI_WIDEBAND_SPEECH_ENABLED)) {
3657 err = mgmt_cmd_status(sk, hdev->id,
3658 MGMT_OP_SET_WIDEBAND_SPEECH,
3659 MGMT_STATUS_REJECTED);
3660 goto unlock;
3661 }
3662
3663 if (cp->val)
3664 changed = !hci_dev_test_and_set_flag(hdev,
3665 HCI_WIDEBAND_SPEECH_ENABLED);
3666 else
3667 changed = hci_dev_test_and_clear_flag(hdev,
3668 HCI_WIDEBAND_SPEECH_ENABLED);
3669
3670 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3671 if (err < 0)
3672 goto unlock;
3673
3674 if (changed)
3675 err = new_settings(hdev, sk);
3676
3677unlock:
3678 hci_dev_unlock(hdev);
3679 return err;
3680}
3681
Marcel Holtmannbc292252020-04-03 21:44:05 +02003682static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3683 void *data, u16 data_len)
3684{
3685 char buf[16];
3686 struct mgmt_rp_read_security_info *rp = (void *)buf;
3687 u16 sec_len = 0;
3688 u8 flags = 0;
3689
3690 bt_dev_dbg(hdev, "sock %p", sk);
3691
3692 memset(&buf, 0, sizeof(buf));
3693
3694 hci_dev_lock(hdev);
3695
3696 /* When the Read Simple Pairing Options command is supported, then
3697 * the remote public key validation is supported.
3698 */
3699 if (hdev->commands[41] & 0x08)
3700 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3701
3702 flags |= 0x02; /* Remote public key validation (LE) */
3703
3704 /* When the Read Encryption Key Size command is supported, then the
3705 * encryption key size is enforced.
3706 */
3707 if (hdev->commands[20] & 0x10)
3708 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3709
3710 flags |= 0x08; /* Encryption key size enforcement (LE) */
3711
3712 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3713
3714 /* When the Read Simple Pairing Options command is supported, then
3715 * also max encryption key size information is provided.
3716 */
3717 if (hdev->commands[41] & 0x08)
3718 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3719 hdev->max_enc_key_size);
3720
3721 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3722
3723 rp->sec_len = cpu_to_le16(sec_len);
3724
3725 hci_dev_unlock(hdev);
3726
3727 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3728 rp, sizeof(*rp) + sec_len);
3729}
3730
Marcel Holtmanne625e502020-05-06 09:57:52 +02003731#ifdef CONFIG_BT_FEATURE_DEBUG
3732/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3733static const u8 debug_uuid[16] = {
3734 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3735 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3736};
3737#endif
3738
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003739static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3740 void *data, u16 data_len)
3741{
3742 char buf[42];
3743 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3744 u16 idx = 0;
3745
3746 bt_dev_dbg(hdev, "sock %p", sk);
3747
3748 memset(&buf, 0, sizeof(buf));
3749
Marcel Holtmanne625e502020-05-06 09:57:52 +02003750#ifdef CONFIG_BT_FEATURE_DEBUG
3751 if (!hdev) {
3752 u32 flags = bt_dbg_get() ? BIT(0) : 0;
3753
3754 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3755 rp->features[idx].flags = cpu_to_le32(flags);
3756 idx++;
3757 }
3758#endif
3759
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003760 rp->feature_count = cpu_to_le16(idx);
3761
3762 /* After reading the experimental features information, enable
3763 * the events to update client on any future change.
3764 */
3765 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3766
3767 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3768 MGMT_OP_READ_EXP_FEATURES_INFO,
3769 0, rp, sizeof(*rp) + (20 * idx));
3770}
3771
Marcel Holtmanne625e502020-05-06 09:57:52 +02003772#ifdef CONFIG_BT_FEATURE_DEBUG
3773static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3774{
3775 struct mgmt_ev_exp_feature_changed ev;
3776
3777 memset(&ev, 0, sizeof(ev));
3778 memcpy(ev.uuid, debug_uuid, 16);
3779 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3780
3781 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3782 &ev, sizeof(ev),
3783 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3784}
3785#endif
3786
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003787static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3788 void *data, u16 data_len)
3789{
3790 struct mgmt_cp_set_exp_feature *cp = data;
3791 struct mgmt_rp_set_exp_feature rp;
3792
3793 bt_dev_dbg(hdev, "sock %p", sk);
3794
3795 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3796 memset(rp.uuid, 0, 16);
3797 rp.flags = cpu_to_le32(0);
3798
Marcel Holtmanne625e502020-05-06 09:57:52 +02003799#ifdef CONFIG_BT_FEATURE_DEBUG
3800 if (!hdev) {
3801 bool changed = bt_dbg_get();
3802
3803 bt_dbg_set(false);
3804
3805 if (changed)
3806 exp_debug_feature_changed(false, sk);
3807 }
3808#endif
3809
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003810 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3811
3812 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3813 MGMT_OP_SET_EXP_FEATURE, 0,
3814 &rp, sizeof(rp));
3815 }
3816
Marcel Holtmanne625e502020-05-06 09:57:52 +02003817#ifdef CONFIG_BT_FEATURE_DEBUG
3818 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3819 bool val, changed;
3820 int err;
3821
3822 /* Command requires to use the non-controller index */
3823 if (hdev)
3824 return mgmt_cmd_status(sk, hdev->id,
3825 MGMT_OP_SET_EXP_FEATURE,
3826 MGMT_STATUS_INVALID_INDEX);
3827
3828 /* Parameters are limited to a single octet */
3829 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3830 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3831 MGMT_OP_SET_EXP_FEATURE,
3832 MGMT_STATUS_INVALID_PARAMS);
3833
3834 /* Only boolean on/off is supported */
3835 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3836 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3837 MGMT_OP_SET_EXP_FEATURE,
3838 MGMT_STATUS_INVALID_PARAMS);
3839
3840 val = !!cp->param[0];
3841 changed = val ? !bt_dbg_get() : bt_dbg_get();
3842 bt_dbg_set(val);
3843
3844 memcpy(rp.uuid, debug_uuid, 16);
3845 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3846
3847 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3848
3849 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3850 MGMT_OP_SET_EXP_FEATURE, 0,
3851 &rp, sizeof(rp));
3852
3853 if (changed)
3854 exp_debug_feature_changed(val, sk);
3855
3856 return err;
3857 }
3858#endif
3859
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003860 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3861 MGMT_OP_SET_EXP_FEATURE,
3862 MGMT_STATUS_NOT_SUPPORTED);
3863}
3864
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003865#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
3866
3867static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3868 u16 data_len)
3869{
3870 struct mgmt_cp_get_device_flags *cp = data;
3871 struct mgmt_rp_get_device_flags rp;
3872 struct bdaddr_list_with_flags *br_params;
3873 struct hci_conn_params *params;
3874 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3875 u32 current_flags = 0;
3876 u8 status = MGMT_STATUS_INVALID_PARAMS;
3877
3878 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
3879 &cp->addr.bdaddr, cp->addr.type);
3880
3881 if (cp->addr.type == BDADDR_BREDR) {
3882 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3883 &cp->addr.bdaddr,
3884 cp->addr.type);
3885 if (!br_params)
3886 goto done;
3887
3888 current_flags = br_params->current_flags;
3889 } else {
3890 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
3891 le_addr_type(cp->addr.type));
3892
3893 if (!params)
3894 goto done;
3895
3896 current_flags = params->current_flags;
3897 }
3898
3899 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3900 rp.addr.type = cp->addr.type;
3901 rp.supported_flags = cpu_to_le32(supported_flags);
3902 rp.current_flags = cpu_to_le32(current_flags);
3903
3904 status = MGMT_STATUS_SUCCESS;
3905
3906done:
3907 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
3908 &rp, sizeof(rp));
3909}
3910
3911static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
3912 bdaddr_t *bdaddr, u8 bdaddr_type,
3913 u32 supported_flags, u32 current_flags)
3914{
3915 struct mgmt_ev_device_flags_changed ev;
3916
3917 bacpy(&ev.addr.bdaddr, bdaddr);
3918 ev.addr.type = bdaddr_type;
3919 ev.supported_flags = cpu_to_le32(supported_flags);
3920 ev.current_flags = cpu_to_le32(current_flags);
3921
3922 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
3923}
3924
3925static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3926 u16 len)
3927{
3928 struct mgmt_cp_set_device_flags *cp = data;
3929 struct bdaddr_list_with_flags *br_params;
3930 struct hci_conn_params *params;
3931 u8 status = MGMT_STATUS_INVALID_PARAMS;
3932 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3933 u32 current_flags = __le32_to_cpu(cp->current_flags);
3934
3935 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
3936 &cp->addr.bdaddr, cp->addr.type,
3937 __le32_to_cpu(current_flags));
3938
3939 if ((supported_flags | current_flags) != supported_flags) {
3940 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
3941 current_flags, supported_flags);
3942 goto done;
3943 }
3944
3945 if (cp->addr.type == BDADDR_BREDR) {
3946 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3947 &cp->addr.bdaddr,
3948 cp->addr.type);
3949
3950 if (br_params) {
3951 br_params->current_flags = current_flags;
3952 status = MGMT_STATUS_SUCCESS;
3953 } else {
3954 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
3955 &cp->addr.bdaddr, cp->addr.type);
3956 }
3957 } else {
3958 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
3959 le_addr_type(cp->addr.type));
3960 if (params) {
3961 params->current_flags = current_flags;
3962 status = MGMT_STATUS_SUCCESS;
3963 } else {
3964 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
3965 &cp->addr.bdaddr,
3966 le_addr_type(cp->addr.type));
3967 }
3968 }
3969
3970done:
3971 if (status == MGMT_STATUS_SUCCESS)
3972 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
3973 supported_flags, current_flags);
3974
3975 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
3976 &cp->addr, sizeof(cp->addr));
3977}
3978
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02003979static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
3980 void *data, u16 len)
3981{
3982 struct adv_monitor *monitor = NULL;
3983 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
3984 int handle;
3985 size_t rp_size = 0;
3986 __u32 supported = 0;
3987 __u16 num_handles = 0;
3988 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
3989
3990 BT_DBG("request for %s", hdev->name);
3991
3992 hci_dev_lock(hdev);
3993
3994 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
3995 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
3996
3997 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
3998 handles[num_handles++] = monitor->handle;
3999 }
4000
4001 hci_dev_unlock(hdev);
4002
4003 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4004 rp = kmalloc(rp_size, GFP_KERNEL);
4005 if (!rp)
4006 return -ENOMEM;
4007
4008 /* Once controller-based monitoring is in place, the enabled_features
4009 * should reflect the use.
4010 */
4011 rp->supported_features = cpu_to_le32(supported);
4012 rp->enabled_features = 0;
4013 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4014 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4015 rp->num_handles = cpu_to_le16(num_handles);
4016 if (num_handles)
4017 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4018
4019 return mgmt_cmd_complete(sk, hdev->id,
4020 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4021 MGMT_STATUS_SUCCESS, rp, rp_size);
4022}
4023
Miao-chen Choub1395532020-06-17 16:39:14 +02004024static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4025 void *data, u16 len)
4026{
4027 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4028 struct mgmt_rp_add_adv_patterns_monitor rp;
4029 struct adv_monitor *m = NULL;
4030 struct adv_pattern *p = NULL;
4031 __u8 cp_ofst = 0, cp_len = 0;
4032 unsigned int mp_cnt = 0;
4033 int err, i;
4034
4035 BT_DBG("request for %s", hdev->name);
4036
4037 if (len <= sizeof(*cp) || cp->pattern_count == 0) {
4038 err = mgmt_cmd_status(sk, hdev->id,
4039 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4040 MGMT_STATUS_INVALID_PARAMS);
4041 goto failed;
4042 }
4043
4044 m = kmalloc(sizeof(*m), GFP_KERNEL);
4045 if (!m) {
4046 err = -ENOMEM;
4047 goto failed;
4048 }
4049
4050 INIT_LIST_HEAD(&m->patterns);
4051 m->active = false;
4052
4053 for (i = 0; i < cp->pattern_count; i++) {
4054 if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
4055 err = mgmt_cmd_status(sk, hdev->id,
4056 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4057 MGMT_STATUS_INVALID_PARAMS);
4058 goto failed;
4059 }
4060
4061 cp_ofst = cp->patterns[i].offset;
4062 cp_len = cp->patterns[i].length;
4063 if (cp_ofst >= HCI_MAX_AD_LENGTH ||
4064 cp_len > HCI_MAX_AD_LENGTH ||
4065 (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
4066 err = mgmt_cmd_status(sk, hdev->id,
4067 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4068 MGMT_STATUS_INVALID_PARAMS);
4069 goto failed;
4070 }
4071
4072 p = kmalloc(sizeof(*p), GFP_KERNEL);
4073 if (!p) {
4074 err = -ENOMEM;
4075 goto failed;
4076 }
4077
4078 p->ad_type = cp->patterns[i].ad_type;
4079 p->offset = cp->patterns[i].offset;
4080 p->length = cp->patterns[i].length;
4081 memcpy(p->value, cp->patterns[i].value, p->length);
4082
4083 INIT_LIST_HEAD(&p->list);
4084 list_add(&p->list, &m->patterns);
4085 }
4086
4087 if (mp_cnt != cp->pattern_count) {
4088 err = mgmt_cmd_status(sk, hdev->id,
4089 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4090 MGMT_STATUS_INVALID_PARAMS);
4091 goto failed;
4092 }
4093
4094 hci_dev_lock(hdev);
4095
4096 err = hci_add_adv_monitor(hdev, m);
4097 if (err) {
4098 if (err == -ENOSPC) {
4099 mgmt_cmd_status(sk, hdev->id,
4100 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4101 MGMT_STATUS_NO_RESOURCES);
4102 }
4103 goto unlock;
4104 }
4105
4106 hci_dev_unlock(hdev);
4107
4108 rp.monitor_handle = cpu_to_le16(m->handle);
4109
4110 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4111 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4112
4113unlock:
4114 hci_dev_unlock(hdev);
4115
4116failed:
4117 hci_free_adv_monitor(m);
4118 return err;
4119}
4120
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004121static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4122 u16 opcode, struct sk_buff *skb)
4123{
4124 struct mgmt_rp_read_local_oob_data mgmt_rp;
4125 size_t rp_size = sizeof(mgmt_rp);
4126 struct mgmt_pending_cmd *cmd;
4127
Marcel Holtmann181d6952020-05-06 09:57:47 +02004128 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004129
4130 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4131 if (!cmd)
4132 return;
4133
4134 if (status || !skb) {
4135 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4136 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4137 goto remove;
4138 }
4139
4140 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4141
4142 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4143 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4144
4145 if (skb->len < sizeof(*rp)) {
4146 mgmt_cmd_status(cmd->sk, hdev->id,
4147 MGMT_OP_READ_LOCAL_OOB_DATA,
4148 MGMT_STATUS_FAILED);
4149 goto remove;
4150 }
4151
4152 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4153 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4154
4155 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4156 } else {
4157 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4158
4159 if (skb->len < sizeof(*rp)) {
4160 mgmt_cmd_status(cmd->sk, hdev->id,
4161 MGMT_OP_READ_LOCAL_OOB_DATA,
4162 MGMT_STATUS_FAILED);
4163 goto remove;
4164 }
4165
4166 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4167 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4168
4169 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4170 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4171 }
4172
4173 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4174 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4175
4176remove:
4177 mgmt_pending_remove(cmd);
4178}
4179
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004180static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004181 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004182{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004183 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004184 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004185 int err;
4186
Marcel Holtmann181d6952020-05-06 09:57:47 +02004187 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004189 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004190
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004191 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004192 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4193 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004194 goto unlock;
4195 }
4196
Andre Guedes9a1a1992012-07-24 15:03:48 -03004197 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004198 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4199 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004200 goto unlock;
4201 }
4202
Johan Hedberg333ae952015-03-17 13:48:47 +02004203 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004204 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4205 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004206 goto unlock;
4207 }
4208
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004209 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004210 if (!cmd) {
4211 err = -ENOMEM;
4212 goto unlock;
4213 }
4214
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004215 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004216
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004217 if (bredr_sc_enabled(hdev))
4218 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4219 else
4220 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4221
4222 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004223 if (err < 0)
4224 mgmt_pending_remove(cmd);
4225
4226unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004227 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004228 return err;
4229}
4230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004231static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004232 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004233{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004234 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004235 int err;
4236
Marcel Holtmann181d6952020-05-06 09:57:47 +02004237 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004238
Johan Hedberg5d57e792015-01-23 10:10:38 +02004239 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004240 return mgmt_cmd_complete(sk, hdev->id,
4241 MGMT_OP_ADD_REMOTE_OOB_DATA,
4242 MGMT_STATUS_INVALID_PARAMS,
4243 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004244
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004245 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004246
Marcel Holtmannec109112014-01-10 02:07:30 -08004247 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4248 struct mgmt_cp_add_remote_oob_data *cp = data;
4249 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004250
Johan Hedbergc19a4952014-11-17 20:52:19 +02004251 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004252 err = mgmt_cmd_complete(sk, hdev->id,
4253 MGMT_OP_ADD_REMOTE_OOB_DATA,
4254 MGMT_STATUS_INVALID_PARAMS,
4255 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004256 goto unlock;
4257 }
4258
Marcel Holtmannec109112014-01-10 02:07:30 -08004259 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004260 cp->addr.type, cp->hash,
4261 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004262 if (err < 0)
4263 status = MGMT_STATUS_FAILED;
4264 else
4265 status = MGMT_STATUS_SUCCESS;
4266
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004267 err = mgmt_cmd_complete(sk, hdev->id,
4268 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4269 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004270 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4271 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004272 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004273 u8 status;
4274
Johan Hedberg86df9202014-10-26 20:52:27 +01004275 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004276 /* Enforce zero-valued 192-bit parameters as
4277 * long as legacy SMP OOB isn't implemented.
4278 */
4279 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4280 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004281 err = mgmt_cmd_complete(sk, hdev->id,
4282 MGMT_OP_ADD_REMOTE_OOB_DATA,
4283 MGMT_STATUS_INVALID_PARAMS,
4284 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004285 goto unlock;
4286 }
4287
Johan Hedberg86df9202014-10-26 20:52:27 +01004288 rand192 = NULL;
4289 hash192 = NULL;
4290 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004291 /* In case one of the P-192 values is set to zero,
4292 * then just disable OOB data for P-192.
4293 */
4294 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4295 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4296 rand192 = NULL;
4297 hash192 = NULL;
4298 } else {
4299 rand192 = cp->rand192;
4300 hash192 = cp->hash192;
4301 }
4302 }
4303
4304 /* In case one of the P-256 values is set to zero, then just
4305 * disable OOB data for P-256.
4306 */
4307 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4308 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4309 rand256 = NULL;
4310 hash256 = NULL;
4311 } else {
4312 rand256 = cp->rand256;
4313 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004314 }
4315
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004316 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004317 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004318 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004319 if (err < 0)
4320 status = MGMT_STATUS_FAILED;
4321 else
4322 status = MGMT_STATUS_SUCCESS;
4323
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004324 err = mgmt_cmd_complete(sk, hdev->id,
4325 MGMT_OP_ADD_REMOTE_OOB_DATA,
4326 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004327 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004328 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4329 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004330 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4331 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004332 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004333
Johan Hedbergc19a4952014-11-17 20:52:19 +02004334unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004335 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004336 return err;
4337}
4338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004339static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004340 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004341{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004342 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004343 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004344 int err;
4345
Marcel Holtmann181d6952020-05-06 09:57:47 +02004346 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004347
Johan Hedbergc19a4952014-11-17 20:52:19 +02004348 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004349 return mgmt_cmd_complete(sk, hdev->id,
4350 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4351 MGMT_STATUS_INVALID_PARAMS,
4352 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004354 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004355
Johan Hedbergeedbd582014-11-15 09:34:23 +02004356 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4357 hci_remote_oob_data_clear(hdev);
4358 status = MGMT_STATUS_SUCCESS;
4359 goto done;
4360 }
4361
Johan Hedberg6928a922014-10-26 20:46:09 +01004362 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004363 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004364 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004365 else
Szymon Janca6785be2012-12-13 15:11:21 +01004366 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004367
Johan Hedbergeedbd582014-11-15 09:34:23 +02004368done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004369 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4370 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004372 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004373 return err;
4374}
4375
Johan Hedberge68f0722015-11-11 08:30:30 +02004376void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004377{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004378 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004379
Marcel Holtmann181d6952020-05-06 09:57:47 +02004380 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004381
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004382 hci_dev_lock(hdev);
4383
Johan Hedberg333ae952015-03-17 13:48:47 +02004384 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004385 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004386 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004387
Johan Hedberg78b781c2016-01-05 13:19:32 +02004388 if (!cmd)
4389 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4390
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004391 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004392 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004393 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004394 }
4395
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004396 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004397
4398 /* Handle suspend notifier */
4399 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4400 hdev->suspend_tasks)) {
4401 bt_dev_dbg(hdev, "Unpaused discovery");
4402 wake_up(&hdev->suspend_wait_q);
4403 }
Andre Guedes7c307722013-04-30 15:29:28 -03004404}
4405
Johan Hedberg591752a2015-11-11 08:11:24 +02004406static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4407 uint8_t *mgmt_status)
4408{
4409 switch (type) {
4410 case DISCOV_TYPE_LE:
4411 *mgmt_status = mgmt_le_support(hdev);
4412 if (*mgmt_status)
4413 return false;
4414 break;
4415 case DISCOV_TYPE_INTERLEAVED:
4416 *mgmt_status = mgmt_le_support(hdev);
4417 if (*mgmt_status)
4418 return false;
4419 /* Intentional fall-through */
4420 case DISCOV_TYPE_BREDR:
4421 *mgmt_status = mgmt_bredr_support(hdev);
4422 if (*mgmt_status)
4423 return false;
4424 break;
4425 default:
4426 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4427 return false;
4428 }
4429
4430 return true;
4431}
4432
Johan Hedberg78b781c2016-01-05 13:19:32 +02004433static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4434 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004435{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004436 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004437 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004438 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004439 int err;
4440
Marcel Holtmann181d6952020-05-06 09:57:47 +02004441 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004443 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004444
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004445 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004446 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004447 MGMT_STATUS_NOT_POWERED,
4448 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004449 goto failed;
4450 }
4451
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004452 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004453 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004454 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4455 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004456 goto failed;
4457 }
4458
Johan Hedberg591752a2015-11-11 08:11:24 +02004459 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004460 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4461 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004462 goto failed;
4463 }
4464
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004465 /* Can't start discovery when it is paused */
4466 if (hdev->discovery_paused) {
4467 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4468 &cp->type, sizeof(cp->type));
4469 goto failed;
4470 }
4471
Marcel Holtmann22078802014-12-05 11:45:22 +01004472 /* Clear the discovery filter first to free any previously
4473 * allocated memory for the UUID list.
4474 */
4475 hci_discovery_filter_clear(hdev);
4476
Andre Guedes4aab14e2012-02-17 20:39:36 -03004477 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004478 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004479 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4480 hdev->discovery.limited = true;
4481 else
4482 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004483
Johan Hedberg78b781c2016-01-05 13:19:32 +02004484 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004485 if (!cmd) {
4486 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004487 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004488 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004489
Johan Hedberge68f0722015-11-11 08:30:30 +02004490 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004491
4492 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004493 queue_work(hdev->req_workqueue, &hdev->discov_update);
4494 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004495
4496failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004497 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004498 return err;
4499}
4500
Johan Hedberg78b781c2016-01-05 13:19:32 +02004501static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4502 void *data, u16 len)
4503{
4504 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4505 data, len);
4506}
4507
4508static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4509 void *data, u16 len)
4510{
4511 return start_discovery_internal(sk, hdev,
4512 MGMT_OP_START_LIMITED_DISCOVERY,
4513 data, len);
4514}
4515
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004516static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4517 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004518{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004519 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4520 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004521}
4522
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004523static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4524 void *data, u16 len)
4525{
4526 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004527 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004528 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4529 u16 uuid_count, expected_len;
4530 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004531 int err;
4532
Marcel Holtmann181d6952020-05-06 09:57:47 +02004533 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004534
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004535 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004536
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004537 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004538 err = mgmt_cmd_complete(sk, hdev->id,
4539 MGMT_OP_START_SERVICE_DISCOVERY,
4540 MGMT_STATUS_NOT_POWERED,
4541 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004542 goto failed;
4543 }
4544
4545 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004546 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004547 err = mgmt_cmd_complete(sk, hdev->id,
4548 MGMT_OP_START_SERVICE_DISCOVERY,
4549 MGMT_STATUS_BUSY, &cp->type,
4550 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004551 goto failed;
4552 }
4553
4554 uuid_count = __le16_to_cpu(cp->uuid_count);
4555 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004556 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4557 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004558 err = mgmt_cmd_complete(sk, hdev->id,
4559 MGMT_OP_START_SERVICE_DISCOVERY,
4560 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4561 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004562 goto failed;
4563 }
4564
4565 expected_len = sizeof(*cp) + uuid_count * 16;
4566 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004567 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4568 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004569 err = mgmt_cmd_complete(sk, hdev->id,
4570 MGMT_OP_START_SERVICE_DISCOVERY,
4571 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4572 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004573 goto failed;
4574 }
4575
Johan Hedberg591752a2015-11-11 08:11:24 +02004576 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4577 err = mgmt_cmd_complete(sk, hdev->id,
4578 MGMT_OP_START_SERVICE_DISCOVERY,
4579 status, &cp->type, sizeof(cp->type));
4580 goto failed;
4581 }
4582
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004583 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004584 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004585 if (!cmd) {
4586 err = -ENOMEM;
4587 goto failed;
4588 }
4589
Johan Hedberg2922a942014-12-05 13:36:06 +02004590 cmd->cmd_complete = service_discovery_cmd_complete;
4591
Marcel Holtmann22078802014-12-05 11:45:22 +01004592 /* Clear the discovery filter first to free any previously
4593 * allocated memory for the UUID list.
4594 */
4595 hci_discovery_filter_clear(hdev);
4596
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004597 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004598 hdev->discovery.type = cp->type;
4599 hdev->discovery.rssi = cp->rssi;
4600 hdev->discovery.uuid_count = uuid_count;
4601
4602 if (uuid_count > 0) {
4603 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4604 GFP_KERNEL);
4605 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004606 err = mgmt_cmd_complete(sk, hdev->id,
4607 MGMT_OP_START_SERVICE_DISCOVERY,
4608 MGMT_STATUS_FAILED,
4609 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004610 mgmt_pending_remove(cmd);
4611 goto failed;
4612 }
4613 }
4614
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004615 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004616 queue_work(hdev->req_workqueue, &hdev->discov_update);
4617 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004618
4619failed:
4620 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004621 return err;
4622}
4623
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004624void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004625{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004626 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004627
Marcel Holtmann181d6952020-05-06 09:57:47 +02004628 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004629
4630 hci_dev_lock(hdev);
4631
Johan Hedberg333ae952015-03-17 13:48:47 +02004632 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004633 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004634 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004635 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004636 }
4637
Andre Guedes0e05bba2013-04-30 15:29:33 -03004638 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004639
4640 /* Handle suspend notifier */
4641 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4642 bt_dev_dbg(hdev, "Paused discovery");
4643 wake_up(&hdev->suspend_wait_q);
4644 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004645}
4646
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004647static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004648 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004649{
Johan Hedbergd9306502012-02-20 23:25:18 +02004650 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004651 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004652 int err;
4653
Marcel Holtmann181d6952020-05-06 09:57:47 +02004654 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004656 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004657
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004658 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004659 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4660 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4661 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004662 goto unlock;
4663 }
4664
4665 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004666 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4667 MGMT_STATUS_INVALID_PARAMS,
4668 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004669 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004670 }
4671
Johan Hedberg2922a942014-12-05 13:36:06 +02004672 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004673 if (!cmd) {
4674 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004675 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004676 }
4677
Johan Hedberg2922a942014-12-05 13:36:06 +02004678 cmd->cmd_complete = generic_cmd_complete;
4679
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004680 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4681 queue_work(hdev->req_workqueue, &hdev->discov_update);
4682 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004683
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004684unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004685 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004686 return err;
4687}
4688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004689static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004690 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004691{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004692 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004693 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004694 int err;
4695
Marcel Holtmann181d6952020-05-06 09:57:47 +02004696 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004697
Johan Hedberg561aafb2012-01-04 13:31:59 +02004698 hci_dev_lock(hdev);
4699
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004700 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004701 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4702 MGMT_STATUS_FAILED, &cp->addr,
4703 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004704 goto failed;
4705 }
4706
Johan Hedberga198e7b2012-02-17 14:27:06 +02004707 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004708 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004709 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4710 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4711 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004712 goto failed;
4713 }
4714
4715 if (cp->name_known) {
4716 e->name_state = NAME_KNOWN;
4717 list_del(&e->list);
4718 } else {
4719 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004720 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004721 }
4722
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004723 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4724 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004725
4726failed:
4727 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004728 return err;
4729}
4730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004731static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004732 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004733{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004734 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004735 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004736 int err;
4737
Marcel Holtmann181d6952020-05-06 09:57:47 +02004738 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004739
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004740 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004741 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4742 MGMT_STATUS_INVALID_PARAMS,
4743 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004745 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004746
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004747 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4748 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004749 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004750 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004751 goto done;
4752 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004753
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004754 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4755 sk);
4756 status = MGMT_STATUS_SUCCESS;
4757
4758done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004759 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4760 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004762 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004763
4764 return err;
4765}
4766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004767static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004768 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004769{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004770 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004771 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004772 int err;
4773
Marcel Holtmann181d6952020-05-06 09:57:47 +02004774 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004775
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004776 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004777 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4778 MGMT_STATUS_INVALID_PARAMS,
4779 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004781 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004782
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004783 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4784 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004785 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004786 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004787 goto done;
4788 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004789
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004790 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4791 sk);
4792 status = MGMT_STATUS_SUCCESS;
4793
4794done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004795 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4796 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004797
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004798 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004799
4800 return err;
4801}
4802
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004803static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4804 u16 len)
4805{
4806 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004807 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004808 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004809 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004810
Marcel Holtmann181d6952020-05-06 09:57:47 +02004811 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004812
Szymon Jancc72d4b82012-03-16 16:02:57 +01004813 source = __le16_to_cpu(cp->source);
4814
4815 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004816 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4817 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004818
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004819 hci_dev_lock(hdev);
4820
Szymon Jancc72d4b82012-03-16 16:02:57 +01004821 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004822 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4823 hdev->devid_product = __le16_to_cpu(cp->product);
4824 hdev->devid_version = __le16_to_cpu(cp->version);
4825
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004826 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4827 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004828
Johan Hedberg890ea892013-03-15 17:06:52 -05004829 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004830 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004831 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004832
4833 hci_dev_unlock(hdev);
4834
4835 return err;
4836}
4837
Arman Uguray24b4f382015-03-23 15:57:12 -07004838static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4839 u16 opcode)
4840{
Marcel Holtmann181d6952020-05-06 09:57:47 +02004841 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07004842}
4843
Marcel Holtmann1904a852015-01-11 13:50:44 -08004844static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4845 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004846{
4847 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004848 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004849 u8 instance;
4850 struct adv_info *adv_instance;
4851 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004852
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304853 hci_dev_lock(hdev);
4854
Johan Hedberg4375f102013-09-25 13:26:10 +03004855 if (status) {
4856 u8 mgmt_err = mgmt_status(status);
4857
4858 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4859 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304860 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004861 }
4862
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004863 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004864 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004865 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004866 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004867
Johan Hedberg4375f102013-09-25 13:26:10 +03004868 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4869 &match);
4870
4871 new_settings(hdev, match.sk);
4872
4873 if (match.sk)
4874 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304875
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004876 /* Handle suspend notifier */
4877 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
4878 hdev->suspend_tasks)) {
4879 bt_dev_dbg(hdev, "Paused advertising");
4880 wake_up(&hdev->suspend_wait_q);
4881 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
4882 hdev->suspend_tasks)) {
4883 bt_dev_dbg(hdev, "Unpaused advertising");
4884 wake_up(&hdev->suspend_wait_q);
4885 }
4886
Arman Uguray24b4f382015-03-23 15:57:12 -07004887 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004888 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004889 */
4890 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004891 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004892 goto unlock;
4893
Florian Grandel7816b822015-06-18 03:16:45 +02004894 instance = hdev->cur_adv_instance;
4895 if (!instance) {
4896 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4897 struct adv_info, list);
4898 if (!adv_instance)
4899 goto unlock;
4900
4901 instance = adv_instance->instance;
4902 }
4903
Arman Uguray24b4f382015-03-23 15:57:12 -07004904 hci_req_init(&req, hdev);
4905
Johan Hedbergf2252572015-11-18 12:49:20 +02004906 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004907
Florian Grandel7816b822015-06-18 03:16:45 +02004908 if (!err)
4909 err = hci_req_run(&req, enable_advertising_instance);
4910
4911 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004912 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004913
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304914unlock:
4915 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004916}
4917
Marcel Holtmann21b51872013-10-10 09:47:53 -07004918static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4919 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004920{
4921 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004922 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004923 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004924 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004925 int err;
4926
Marcel Holtmann181d6952020-05-06 09:57:47 +02004927 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03004928
Johan Hedberge6fe7982013-10-02 15:45:22 +03004929 status = mgmt_le_support(hdev);
4930 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004931 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4932 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004933
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004934 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004935 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4936 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004937
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004938 if (hdev->advertising_paused)
4939 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4940 MGMT_STATUS_BUSY);
4941
Johan Hedberg4375f102013-09-25 13:26:10 +03004942 hci_dev_lock(hdev);
4943
4944 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004945
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004946 /* The following conditions are ones which mean that we should
4947 * not do any HCI communication but directly send a mgmt
4948 * response to user space (after toggling the flag if
4949 * necessary).
4950 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004951 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004952 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4953 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004954 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004955 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004956 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004957 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004958
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004959 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004960 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004961 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004962 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004963 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004964 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004965 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004966 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004967 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004968 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004969 }
4970
4971 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4972 if (err < 0)
4973 goto unlock;
4974
4975 if (changed)
4976 err = new_settings(hdev, sk);
4977
4978 goto unlock;
4979 }
4980
Johan Hedberg333ae952015-03-17 13:48:47 +02004981 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4982 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004983 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4984 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004985 goto unlock;
4986 }
4987
4988 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4989 if (!cmd) {
4990 err = -ENOMEM;
4991 goto unlock;
4992 }
4993
4994 hci_req_init(&req, hdev);
4995
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004996 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004997 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004998 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004999 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07005000
Florian Grandel7816b822015-06-18 03:16:45 +02005001 cancel_adv_timeout(hdev);
5002
Arman Uguray24b4f382015-03-23 15:57:12 -07005003 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005004 /* Switch to instance "0" for the Set Advertising setting.
5005 * We cannot use update_[adv|scan_rsp]_data() here as the
5006 * HCI_ADVERTISING flag is not yet set.
5007 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005008 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305009
5010 if (ext_adv_capable(hdev)) {
5011 __hci_req_start_ext_adv(&req, 0x00);
5012 } else {
5013 __hci_req_update_adv_data(&req, 0x00);
5014 __hci_req_update_scan_rsp_data(&req, 0x00);
5015 __hci_req_enable_advertising(&req);
5016 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005017 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005018 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005019 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005020
5021 err = hci_req_run(&req, set_advertising_complete);
5022 if (err < 0)
5023 mgmt_pending_remove(cmd);
5024
5025unlock:
5026 hci_dev_unlock(hdev);
5027 return err;
5028}
5029
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005030static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5031 void *data, u16 len)
5032{
5033 struct mgmt_cp_set_static_address *cp = data;
5034 int err;
5035
Marcel Holtmann181d6952020-05-06 09:57:47 +02005036 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005037
Marcel Holtmann62af4442013-10-02 22:10:32 -07005038 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005039 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5040 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005041
5042 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005043 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5044 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005045
5046 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5047 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005048 return mgmt_cmd_status(sk, hdev->id,
5049 MGMT_OP_SET_STATIC_ADDRESS,
5050 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005051
5052 /* Two most significant bits shall be set */
5053 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005054 return mgmt_cmd_status(sk, hdev->id,
5055 MGMT_OP_SET_STATIC_ADDRESS,
5056 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005057 }
5058
5059 hci_dev_lock(hdev);
5060
5061 bacpy(&hdev->static_addr, &cp->bdaddr);
5062
Marcel Holtmann93690c22015-03-06 10:11:21 -08005063 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5064 if (err < 0)
5065 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005066
Marcel Holtmann93690c22015-03-06 10:11:21 -08005067 err = new_settings(hdev, sk);
5068
5069unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005070 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005071 return err;
5072}
5073
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005074static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5075 void *data, u16 len)
5076{
5077 struct mgmt_cp_set_scan_params *cp = data;
5078 __u16 interval, window;
5079 int err;
5080
Marcel Holtmann181d6952020-05-06 09:57:47 +02005081 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005082
5083 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005084 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5085 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005086
5087 interval = __le16_to_cpu(cp->interval);
5088
5089 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005090 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5091 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005092
5093 window = __le16_to_cpu(cp->window);
5094
5095 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005096 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5097 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005098
Marcel Holtmann899e1072013-10-14 09:55:32 -07005099 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005100 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5101 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005102
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005103 hci_dev_lock(hdev);
5104
5105 hdev->le_scan_interval = interval;
5106 hdev->le_scan_window = window;
5107
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005108 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5109 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005110
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005111 /* If background scan is running, restart it so new parameters are
5112 * loaded.
5113 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005114 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005115 hdev->discovery.state == DISCOVERY_STOPPED) {
5116 struct hci_request req;
5117
5118 hci_req_init(&req, hdev);
5119
5120 hci_req_add_le_scan_disable(&req);
5121 hci_req_add_le_passive_scan(&req);
5122
5123 hci_req_run(&req, NULL);
5124 }
5125
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005126 hci_dev_unlock(hdev);
5127
5128 return err;
5129}
5130
Marcel Holtmann1904a852015-01-11 13:50:44 -08005131static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5132 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005133{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005134 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005135
Marcel Holtmann181d6952020-05-06 09:57:47 +02005136 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005137
5138 hci_dev_lock(hdev);
5139
Johan Hedberg333ae952015-03-17 13:48:47 +02005140 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005141 if (!cmd)
5142 goto unlock;
5143
5144 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005145 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5146 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005147 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005148 struct mgmt_mode *cp = cmd->param;
5149
5150 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005151 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005152 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005153 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005154
Johan Hedberg33e38b32013-03-15 17:07:05 -05005155 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5156 new_settings(hdev, cmd->sk);
5157 }
5158
5159 mgmt_pending_remove(cmd);
5160
5161unlock:
5162 hci_dev_unlock(hdev);
5163}
5164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005165static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005166 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005167{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005168 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005169 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005170 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005171 int err;
5172
Marcel Holtmann181d6952020-05-06 09:57:47 +02005173 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005174
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005175 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005176 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005177 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5178 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005179
Johan Hedberga7e80f22013-01-09 16:05:19 +02005180 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005181 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5182 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005183
Antti Julkuf6422ec2011-06-22 13:11:56 +03005184 hci_dev_lock(hdev);
5185
Johan Hedberg333ae952015-03-17 13:48:47 +02005186 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005187 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5188 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005189 goto unlock;
5190 }
5191
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005192 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005193 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5194 hdev);
5195 goto unlock;
5196 }
5197
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005198 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005199 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005200 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5201 hdev);
5202 new_settings(hdev, sk);
5203 goto unlock;
5204 }
5205
Johan Hedberg33e38b32013-03-15 17:07:05 -05005206 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5207 data, len);
5208 if (!cmd) {
5209 err = -ENOMEM;
5210 goto unlock;
5211 }
5212
5213 hci_req_init(&req, hdev);
5214
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005215 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005216
5217 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005218 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005219 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5220 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005221 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005222 }
5223
Johan Hedberg33e38b32013-03-15 17:07:05 -05005224unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005225 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005226
Antti Julkuf6422ec2011-06-22 13:11:56 +03005227 return err;
5228}
5229
Marcel Holtmann1904a852015-01-11 13:50:44 -08005230static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005231{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005232 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005233
Marcel Holtmann181d6952020-05-06 09:57:47 +02005234 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005235
5236 hci_dev_lock(hdev);
5237
Johan Hedberg333ae952015-03-17 13:48:47 +02005238 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005239 if (!cmd)
5240 goto unlock;
5241
5242 if (status) {
5243 u8 mgmt_err = mgmt_status(status);
5244
5245 /* We need to restore the flag if related HCI commands
5246 * failed.
5247 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005248 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005249
Johan Hedberga69e8372015-03-06 21:08:53 +02005250 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005251 } else {
5252 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5253 new_settings(hdev, cmd->sk);
5254 }
5255
5256 mgmt_pending_remove(cmd);
5257
5258unlock:
5259 hci_dev_unlock(hdev);
5260}
5261
5262static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5263{
5264 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005265 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005266 struct hci_request req;
5267 int err;
5268
Marcel Holtmann181d6952020-05-06 09:57:47 +02005269 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005270
5271 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005272 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5273 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005274
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005275 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5277 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005278
5279 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005280 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005282
5283 hci_dev_lock(hdev);
5284
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005285 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005286 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5287 goto unlock;
5288 }
5289
5290 if (!hdev_is_powered(hdev)) {
5291 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005292 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5293 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5294 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5295 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5296 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005297 }
5298
Marcel Holtmannce05d602015-03-13 02:11:03 -07005299 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005300
5301 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5302 if (err < 0)
5303 goto unlock;
5304
5305 err = new_settings(hdev, sk);
5306 goto unlock;
5307 }
5308
5309 /* Reject disabling when powered on */
5310 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005311 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5312 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005313 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005314 } else {
5315 /* When configuring a dual-mode controller to operate
5316 * with LE only and using a static address, then switching
5317 * BR/EDR back on is not allowed.
5318 *
5319 * Dual-mode controllers shall operate with the public
5320 * address as its identity address for BR/EDR and LE. So
5321 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005322 *
5323 * The same restrictions applies when secure connections
5324 * has been enabled. For BR/EDR this is a controller feature
5325 * while for LE it is a host stack feature. This means that
5326 * switching BR/EDR back on when secure connections has been
5327 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005328 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005329 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005330 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005331 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005332 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5333 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005334 goto unlock;
5335 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005336 }
5337
Johan Hedberg333ae952015-03-17 13:48:47 +02005338 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005339 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5340 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005341 goto unlock;
5342 }
5343
5344 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5345 if (!cmd) {
5346 err = -ENOMEM;
5347 goto unlock;
5348 }
5349
Johan Hedbergf2252572015-11-18 12:49:20 +02005350 /* We need to flip the bit already here so that
5351 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005352 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005353 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005354
5355 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005356
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005357 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005358 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005359
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005360 /* Since only the advertising data flags will change, there
5361 * is no need to update the scan response data.
5362 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005363 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005364
Johan Hedberg0663ca22013-10-02 13:43:14 +03005365 err = hci_req_run(&req, set_bredr_complete);
5366 if (err < 0)
5367 mgmt_pending_remove(cmd);
5368
5369unlock:
5370 hci_dev_unlock(hdev);
5371 return err;
5372}
5373
Johan Hedberga1443f52015-01-23 15:42:46 +02005374static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5375{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005376 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005377 struct mgmt_mode *cp;
5378
Marcel Holtmann181d6952020-05-06 09:57:47 +02005379 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005380
5381 hci_dev_lock(hdev);
5382
Johan Hedberg333ae952015-03-17 13:48:47 +02005383 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005384 if (!cmd)
5385 goto unlock;
5386
5387 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005388 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5389 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005390 goto remove;
5391 }
5392
5393 cp = cmd->param;
5394
5395 switch (cp->val) {
5396 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005397 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5398 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005399 break;
5400 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005401 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005402 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005403 break;
5404 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005405 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5406 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005407 break;
5408 }
5409
5410 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5411 new_settings(hdev, cmd->sk);
5412
5413remove:
5414 mgmt_pending_remove(cmd);
5415unlock:
5416 hci_dev_unlock(hdev);
5417}
5418
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005419static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5420 void *data, u16 len)
5421{
5422 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005423 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005424 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005425 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005426 int err;
5427
Marcel Holtmann181d6952020-05-06 09:57:47 +02005428 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005429
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005430 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005431 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5433 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005434
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005435 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005436 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005437 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005438 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5439 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005440
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005441 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005442 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005443 MGMT_STATUS_INVALID_PARAMS);
5444
5445 hci_dev_lock(hdev);
5446
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005447 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005448 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005449 bool changed;
5450
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005451 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005452 changed = !hci_dev_test_and_set_flag(hdev,
5453 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005454 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005455 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005456 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005457 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005458 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005459 changed = hci_dev_test_and_clear_flag(hdev,
5460 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005461 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005462 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005463
5464 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5465 if (err < 0)
5466 goto failed;
5467
5468 if (changed)
5469 err = new_settings(hdev, sk);
5470
5471 goto failed;
5472 }
5473
Johan Hedberg333ae952015-03-17 13:48:47 +02005474 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005475 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5476 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005477 goto failed;
5478 }
5479
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005480 val = !!cp->val;
5481
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005482 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5483 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005484 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5485 goto failed;
5486 }
5487
5488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5489 if (!cmd) {
5490 err = -ENOMEM;
5491 goto failed;
5492 }
5493
Johan Hedberga1443f52015-01-23 15:42:46 +02005494 hci_req_init(&req, hdev);
5495 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5496 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005497 if (err < 0) {
5498 mgmt_pending_remove(cmd);
5499 goto failed;
5500 }
5501
5502failed:
5503 hci_dev_unlock(hdev);
5504 return err;
5505}
5506
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005507static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5508 void *data, u16 len)
5509{
5510 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005511 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005512 int err;
5513
Marcel Holtmann181d6952020-05-06 09:57:47 +02005514 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005515
Johan Hedbergb97109792014-06-24 14:00:28 +03005516 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005517 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5518 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005519
5520 hci_dev_lock(hdev);
5521
5522 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005523 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005524 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005525 changed = hci_dev_test_and_clear_flag(hdev,
5526 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005527
Johan Hedbergb97109792014-06-24 14:00:28 +03005528 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005529 use_changed = !hci_dev_test_and_set_flag(hdev,
5530 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005531 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005532 use_changed = hci_dev_test_and_clear_flag(hdev,
5533 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005534
5535 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005536 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005537 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5538 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5539 sizeof(mode), &mode);
5540 }
5541
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005542 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5543 if (err < 0)
5544 goto unlock;
5545
5546 if (changed)
5547 err = new_settings(hdev, sk);
5548
5549unlock:
5550 hci_dev_unlock(hdev);
5551 return err;
5552}
5553
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005554static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5555 u16 len)
5556{
5557 struct mgmt_cp_set_privacy *cp = cp_data;
5558 bool changed;
5559 int err;
5560
Marcel Holtmann181d6952020-05-06 09:57:47 +02005561 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005562
5563 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5565 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005566
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005567 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005568 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5569 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005570
5571 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5573 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005574
5575 hci_dev_lock(hdev);
5576
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005577 /* If user space supports this command it is also expected to
5578 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5579 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005580 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005581
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005582 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005583 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005584 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005585 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305586 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005587 if (cp->privacy == 0x02)
5588 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5589 else
5590 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005591 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005592 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005593 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005594 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305595 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005596 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005597 }
5598
5599 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5600 if (err < 0)
5601 goto unlock;
5602
5603 if (changed)
5604 err = new_settings(hdev, sk);
5605
5606unlock:
5607 hci_dev_unlock(hdev);
5608 return err;
5609}
5610
Johan Hedberg41edf162014-02-18 10:19:35 +02005611static bool irk_is_valid(struct mgmt_irk_info *irk)
5612{
5613 switch (irk->addr.type) {
5614 case BDADDR_LE_PUBLIC:
5615 return true;
5616
5617 case BDADDR_LE_RANDOM:
5618 /* Two most significant bits shall be set */
5619 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5620 return false;
5621 return true;
5622 }
5623
5624 return false;
5625}
5626
5627static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5628 u16 len)
5629{
5630 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005631 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5632 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005633 u16 irk_count, expected_len;
5634 int i, err;
5635
Marcel Holtmann181d6952020-05-06 09:57:47 +02005636 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005637
5638 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005639 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5640 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005641
5642 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005643 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005644 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5645 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005646 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5647 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005648 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005649
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005650 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005651 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005652 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5653 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005654 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5655 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005656 }
5657
Marcel Holtmann181d6952020-05-06 09:57:47 +02005658 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005659
5660 for (i = 0; i < irk_count; i++) {
5661 struct mgmt_irk_info *key = &cp->irks[i];
5662
5663 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005664 return mgmt_cmd_status(sk, hdev->id,
5665 MGMT_OP_LOAD_IRKS,
5666 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005667 }
5668
5669 hci_dev_lock(hdev);
5670
5671 hci_smp_irks_clear(hdev);
5672
5673 for (i = 0; i < irk_count; i++) {
5674 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005675
Alain Michaud600a8742020-01-07 00:43:17 +00005676 if (hci_is_blocked_key(hdev,
5677 HCI_BLOCKED_KEY_TYPE_IRK,
5678 irk->val)) {
5679 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5680 &irk->addr.bdaddr);
5681 continue;
5682 }
5683
Johan Hedberg85813a72015-10-21 18:02:59 +03005684 hci_add_irk(hdev, &irk->addr.bdaddr,
5685 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005686 BDADDR_ANY);
5687 }
5688
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005689 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005690
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005691 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005692
5693 hci_dev_unlock(hdev);
5694
5695 return err;
5696}
5697
Johan Hedberg3f706b72013-01-20 14:27:16 +02005698static bool ltk_is_valid(struct mgmt_ltk_info *key)
5699{
5700 if (key->master != 0x00 && key->master != 0x01)
5701 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005702
5703 switch (key->addr.type) {
5704 case BDADDR_LE_PUBLIC:
5705 return true;
5706
5707 case BDADDR_LE_RANDOM:
5708 /* Two most significant bits shall be set */
5709 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5710 return false;
5711 return true;
5712 }
5713
5714 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005715}
5716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005717static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005718 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005719{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005720 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005721 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5722 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005723 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005724 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005725
Marcel Holtmann181d6952020-05-06 09:57:47 +02005726 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005727
5728 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005729 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5730 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005731
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005732 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005733 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005734 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5735 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005736 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005738 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005739
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005740 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005741 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005742 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5743 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005744 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5745 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005746 }
5747
Marcel Holtmann181d6952020-05-06 09:57:47 +02005748 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005749
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005750 for (i = 0; i < key_count; i++) {
5751 struct mgmt_ltk_info *key = &cp->keys[i];
5752
Johan Hedberg3f706b72013-01-20 14:27:16 +02005753 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005754 return mgmt_cmd_status(sk, hdev->id,
5755 MGMT_OP_LOAD_LONG_TERM_KEYS,
5756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005757 }
5758
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005759 hci_dev_lock(hdev);
5760
5761 hci_smp_ltks_clear(hdev);
5762
5763 for (i = 0; i < key_count; i++) {
5764 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005765 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005766
Alain Michaud600a8742020-01-07 00:43:17 +00005767 if (hci_is_blocked_key(hdev,
5768 HCI_BLOCKED_KEY_TYPE_LTK,
5769 key->val)) {
5770 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5771 &key->addr.bdaddr);
5772 continue;
5773 }
5774
Johan Hedberg61b43352014-05-29 19:36:53 +03005775 switch (key->type) {
5776 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005777 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005778 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005779 break;
5780 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005781 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005782 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005783 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005784 case MGMT_LTK_P256_UNAUTH:
5785 authenticated = 0x00;
5786 type = SMP_LTK_P256;
5787 break;
5788 case MGMT_LTK_P256_AUTH:
5789 authenticated = 0x01;
5790 type = SMP_LTK_P256;
5791 break;
5792 case MGMT_LTK_P256_DEBUG:
5793 authenticated = 0x00;
5794 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005795 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005796 default:
5797 continue;
5798 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005799
Johan Hedberg85813a72015-10-21 18:02:59 +03005800 hci_add_ltk(hdev, &key->addr.bdaddr,
5801 le_addr_type(key->addr.type), type, authenticated,
5802 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005803 }
5804
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005805 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005806 NULL, 0);
5807
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005808 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005809
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005810 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005811}
5812
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005813static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005814{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005815 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005816 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005817 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005818
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005819 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005820
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005821 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005822 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005823 rp.tx_power = conn->tx_power;
5824 rp.max_tx_power = conn->max_tx_power;
5825 } else {
5826 rp.rssi = HCI_RSSI_INVALID;
5827 rp.tx_power = HCI_TX_POWER_INVALID;
5828 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005829 }
5830
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005831 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5832 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005833
5834 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005835 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005836
5837 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005838}
5839
Marcel Holtmann1904a852015-01-11 13:50:44 -08005840static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5841 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005842{
5843 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005844 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005845 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005846 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005847 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005848
Marcel Holtmann181d6952020-05-06 09:57:47 +02005849 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005850
5851 hci_dev_lock(hdev);
5852
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005853 /* Commands sent in request are either Read RSSI or Read Transmit Power
5854 * Level so we check which one was last sent to retrieve connection
5855 * handle. Both commands have handle as first parameter so it's safe to
5856 * cast data on the same command struct.
5857 *
5858 * First command sent is always Read RSSI and we fail only if it fails.
5859 * In other case we simply override error to indicate success as we
5860 * already remembered if TX power value is actually valid.
5861 */
5862 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5863 if (!cp) {
5864 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005865 status = MGMT_STATUS_SUCCESS;
5866 } else {
5867 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005868 }
5869
5870 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005871 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005872 goto unlock;
5873 }
5874
5875 handle = __le16_to_cpu(cp->handle);
5876 conn = hci_conn_hash_lookup_handle(hdev, handle);
5877 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005878 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5879 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005880 goto unlock;
5881 }
5882
Johan Hedberg333ae952015-03-17 13:48:47 +02005883 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005884 if (!cmd)
5885 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005886
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005887 cmd->cmd_complete(cmd, status);
5888 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005889
5890unlock:
5891 hci_dev_unlock(hdev);
5892}
5893
5894static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5895 u16 len)
5896{
5897 struct mgmt_cp_get_conn_info *cp = data;
5898 struct mgmt_rp_get_conn_info rp;
5899 struct hci_conn *conn;
5900 unsigned long conn_info_age;
5901 int err = 0;
5902
Marcel Holtmann181d6952020-05-06 09:57:47 +02005903 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005904
5905 memset(&rp, 0, sizeof(rp));
5906 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5907 rp.addr.type = cp->addr.type;
5908
5909 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005910 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5911 MGMT_STATUS_INVALID_PARAMS,
5912 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005913
5914 hci_dev_lock(hdev);
5915
5916 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005917 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5918 MGMT_STATUS_NOT_POWERED, &rp,
5919 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005920 goto unlock;
5921 }
5922
5923 if (cp->addr.type == BDADDR_BREDR)
5924 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5925 &cp->addr.bdaddr);
5926 else
5927 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5928
5929 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5931 MGMT_STATUS_NOT_CONNECTED, &rp,
5932 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005933 goto unlock;
5934 }
5935
Johan Hedberg333ae952015-03-17 13:48:47 +02005936 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005937 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5938 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005939 goto unlock;
5940 }
5941
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005942 /* To avoid client trying to guess when to poll again for information we
5943 * calculate conn info age as random value between min/max set in hdev.
5944 */
5945 conn_info_age = hdev->conn_info_min_age +
5946 prandom_u32_max(hdev->conn_info_max_age -
5947 hdev->conn_info_min_age);
5948
5949 /* Query controller to refresh cached values if they are too old or were
5950 * never read.
5951 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005952 if (time_after(jiffies, conn->conn_info_timestamp +
5953 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005954 !conn->conn_info_timestamp) {
5955 struct hci_request req;
5956 struct hci_cp_read_tx_power req_txp_cp;
5957 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005958 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005959
5960 hci_req_init(&req, hdev);
5961 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5962 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5963 &req_rssi_cp);
5964
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005965 /* For LE links TX power does not change thus we don't need to
5966 * query for it once value is known.
5967 */
5968 if (!bdaddr_type_is_le(cp->addr.type) ||
5969 conn->tx_power == HCI_TX_POWER_INVALID) {
5970 req_txp_cp.handle = cpu_to_le16(conn->handle);
5971 req_txp_cp.type = 0x00;
5972 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5973 sizeof(req_txp_cp), &req_txp_cp);
5974 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005975
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005976 /* Max TX power needs to be read only once per connection */
5977 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5978 req_txp_cp.handle = cpu_to_le16(conn->handle);
5979 req_txp_cp.type = 0x01;
5980 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5981 sizeof(req_txp_cp), &req_txp_cp);
5982 }
5983
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005984 err = hci_req_run(&req, conn_info_refresh_complete);
5985 if (err < 0)
5986 goto unlock;
5987
5988 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5989 data, len);
5990 if (!cmd) {
5991 err = -ENOMEM;
5992 goto unlock;
5993 }
5994
5995 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005996 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005997 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005998
5999 conn->conn_info_timestamp = jiffies;
6000 } else {
6001 /* Cache is valid, just reply with values cached in hci_conn */
6002 rp.rssi = conn->rssi;
6003 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006004 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006005
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006006 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6007 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006008 }
6009
6010unlock:
6011 hci_dev_unlock(hdev);
6012 return err;
6013}
6014
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006015static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006016{
6017 struct hci_conn *conn = cmd->user_data;
6018 struct mgmt_rp_get_clock_info rp;
6019 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006020 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006021
6022 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006023 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006024
6025 if (status)
6026 goto complete;
6027
6028 hdev = hci_dev_get(cmd->index);
6029 if (hdev) {
6030 rp.local_clock = cpu_to_le32(hdev->clock);
6031 hci_dev_put(hdev);
6032 }
6033
6034 if (conn) {
6035 rp.piconet_clock = cpu_to_le32(conn->clock);
6036 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6037 }
6038
6039complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006040 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6041 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006042
6043 if (conn) {
6044 hci_conn_drop(conn);
6045 hci_conn_put(conn);
6046 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006047
6048 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006049}
6050
Marcel Holtmann1904a852015-01-11 13:50:44 -08006051static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006052{
Johan Hedberg95868422014-06-28 17:54:07 +03006053 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006054 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006055 struct hci_conn *conn;
6056
Marcel Holtmann181d6952020-05-06 09:57:47 +02006057 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006058
6059 hci_dev_lock(hdev);
6060
6061 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6062 if (!hci_cp)
6063 goto unlock;
6064
6065 if (hci_cp->which) {
6066 u16 handle = __le16_to_cpu(hci_cp->handle);
6067 conn = hci_conn_hash_lookup_handle(hdev, handle);
6068 } else {
6069 conn = NULL;
6070 }
6071
Johan Hedberg333ae952015-03-17 13:48:47 +02006072 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006073 if (!cmd)
6074 goto unlock;
6075
Johan Hedberg69487372014-12-05 13:36:07 +02006076 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006077 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006078
6079unlock:
6080 hci_dev_unlock(hdev);
6081}
6082
6083static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6084 u16 len)
6085{
6086 struct mgmt_cp_get_clock_info *cp = data;
6087 struct mgmt_rp_get_clock_info rp;
6088 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006089 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006090 struct hci_request req;
6091 struct hci_conn *conn;
6092 int err;
6093
Marcel Holtmann181d6952020-05-06 09:57:47 +02006094 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006095
6096 memset(&rp, 0, sizeof(rp));
6097 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6098 rp.addr.type = cp->addr.type;
6099
6100 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006101 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6102 MGMT_STATUS_INVALID_PARAMS,
6103 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006104
6105 hci_dev_lock(hdev);
6106
6107 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006108 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6109 MGMT_STATUS_NOT_POWERED, &rp,
6110 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006111 goto unlock;
6112 }
6113
6114 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6115 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6116 &cp->addr.bdaddr);
6117 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006118 err = mgmt_cmd_complete(sk, hdev->id,
6119 MGMT_OP_GET_CLOCK_INFO,
6120 MGMT_STATUS_NOT_CONNECTED,
6121 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006122 goto unlock;
6123 }
6124 } else {
6125 conn = NULL;
6126 }
6127
6128 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6129 if (!cmd) {
6130 err = -ENOMEM;
6131 goto unlock;
6132 }
6133
Johan Hedberg69487372014-12-05 13:36:07 +02006134 cmd->cmd_complete = clock_info_cmd_complete;
6135
Johan Hedberg95868422014-06-28 17:54:07 +03006136 hci_req_init(&req, hdev);
6137
6138 memset(&hci_cp, 0, sizeof(hci_cp));
6139 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6140
6141 if (conn) {
6142 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006143 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006144
6145 hci_cp.handle = cpu_to_le16(conn->handle);
6146 hci_cp.which = 0x01; /* Piconet clock */
6147 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6148 }
6149
6150 err = hci_req_run(&req, get_clock_info_complete);
6151 if (err < 0)
6152 mgmt_pending_remove(cmd);
6153
6154unlock:
6155 hci_dev_unlock(hdev);
6156 return err;
6157}
6158
Johan Hedberg5a154e62014-12-19 22:26:02 +02006159static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6160{
6161 struct hci_conn *conn;
6162
6163 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6164 if (!conn)
6165 return false;
6166
6167 if (conn->dst_type != type)
6168 return false;
6169
6170 if (conn->state != BT_CONNECTED)
6171 return false;
6172
6173 return true;
6174}
6175
6176/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006177static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006178 u8 addr_type, u8 auto_connect)
6179{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006180 struct hci_conn_params *params;
6181
6182 params = hci_conn_params_add(hdev, addr, addr_type);
6183 if (!params)
6184 return -EIO;
6185
6186 if (params->auto_connect == auto_connect)
6187 return 0;
6188
6189 list_del_init(&params->action);
6190
6191 switch (auto_connect) {
6192 case HCI_AUTO_CONN_DISABLED:
6193 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006194 /* If auto connect is being disabled when we're trying to
6195 * connect to device, keep connecting.
6196 */
6197 if (params->explicit_connect)
6198 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006199 break;
6200 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006201 if (params->explicit_connect)
6202 list_add(&params->action, &hdev->pend_le_conns);
6203 else
6204 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006205 break;
6206 case HCI_AUTO_CONN_DIRECT:
6207 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006208 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006209 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006210 break;
6211 }
6212
6213 params->auto_connect = auto_connect;
6214
Marcel Holtmann181d6952020-05-06 09:57:47 +02006215 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6216 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006217
6218 return 0;
6219}
6220
Marcel Holtmann8afef092014-06-29 22:28:34 +02006221static void device_added(struct sock *sk, struct hci_dev *hdev,
6222 bdaddr_t *bdaddr, u8 type, u8 action)
6223{
6224 struct mgmt_ev_device_added ev;
6225
6226 bacpy(&ev.addr.bdaddr, bdaddr);
6227 ev.addr.type = type;
6228 ev.action = action;
6229
6230 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6231}
6232
Marcel Holtmann2faade52014-06-29 19:44:03 +02006233static int add_device(struct sock *sk, struct hci_dev *hdev,
6234 void *data, u16 len)
6235{
6236 struct mgmt_cp_add_device *cp = data;
6237 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006238 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006239 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006240 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006241
Marcel Holtmann181d6952020-05-06 09:57:47 +02006242 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006243
Johan Hedberg66593582014-07-09 12:59:14 +03006244 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006245 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006246 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6247 MGMT_STATUS_INVALID_PARAMS,
6248 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006249
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006250 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006251 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6252 MGMT_STATUS_INVALID_PARAMS,
6253 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006254
6255 hci_dev_lock(hdev);
6256
Johan Hedberg66593582014-07-09 12:59:14 +03006257 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006258 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006259 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006260 err = mgmt_cmd_complete(sk, hdev->id,
6261 MGMT_OP_ADD_DEVICE,
6262 MGMT_STATUS_INVALID_PARAMS,
6263 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006264 goto unlock;
6265 }
6266
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006267 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6268 &cp->addr.bdaddr,
6269 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006270 if (err)
6271 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006272
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006273 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006274
Johan Hedberg66593582014-07-09 12:59:14 +03006275 goto added;
6276 }
6277
Johan Hedberg85813a72015-10-21 18:02:59 +03006278 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006279
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006280 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006281 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006282 else if (cp->action == 0x01)
6283 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006284 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006285 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006286
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006287 /* Kernel internally uses conn_params with resolvable private
6288 * address, but Add Device allows only identity addresses.
6289 * Make sure it is enforced before calling
6290 * hci_conn_params_lookup.
6291 */
6292 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006293 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6294 MGMT_STATUS_INVALID_PARAMS,
6295 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006296 goto unlock;
6297 }
6298
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006299 /* If the connection parameters don't exist for this device,
6300 * they will be created and configured with defaults.
6301 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006302 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006303 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006304 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6305 MGMT_STATUS_FAILED, &cp->addr,
6306 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006307 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006308 } else {
6309 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6310 addr_type);
6311 if (params)
6312 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006313 }
6314
Johan Hedberg51d7a942015-11-11 08:11:18 +02006315 hci_update_background_scan(hdev);
6316
Johan Hedberg66593582014-07-09 12:59:14 +03006317added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006318 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006319 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6320 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006321
Johan Hedberg51d7a942015-11-11 08:11:18 +02006322 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6323 MGMT_STATUS_SUCCESS, &cp->addr,
6324 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006325
6326unlock:
6327 hci_dev_unlock(hdev);
6328 return err;
6329}
6330
Marcel Holtmann8afef092014-06-29 22:28:34 +02006331static void device_removed(struct sock *sk, struct hci_dev *hdev,
6332 bdaddr_t *bdaddr, u8 type)
6333{
6334 struct mgmt_ev_device_removed ev;
6335
6336 bacpy(&ev.addr.bdaddr, bdaddr);
6337 ev.addr.type = type;
6338
6339 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6340}
6341
Marcel Holtmann2faade52014-06-29 19:44:03 +02006342static int remove_device(struct sock *sk, struct hci_dev *hdev,
6343 void *data, u16 len)
6344{
6345 struct mgmt_cp_remove_device *cp = data;
6346 int err;
6347
Marcel Holtmann181d6952020-05-06 09:57:47 +02006348 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006349
6350 hci_dev_lock(hdev);
6351
6352 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006353 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006354 u8 addr_type;
6355
Johan Hedberg66593582014-07-09 12:59:14 +03006356 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006357 err = mgmt_cmd_complete(sk, hdev->id,
6358 MGMT_OP_REMOVE_DEVICE,
6359 MGMT_STATUS_INVALID_PARAMS,
6360 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006361 goto unlock;
6362 }
6363
Johan Hedberg66593582014-07-09 12:59:14 +03006364 if (cp->addr.type == BDADDR_BREDR) {
6365 err = hci_bdaddr_list_del(&hdev->whitelist,
6366 &cp->addr.bdaddr,
6367 cp->addr.type);
6368 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006369 err = mgmt_cmd_complete(sk, hdev->id,
6370 MGMT_OP_REMOVE_DEVICE,
6371 MGMT_STATUS_INVALID_PARAMS,
6372 &cp->addr,
6373 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006374 goto unlock;
6375 }
6376
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006377 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006378
Johan Hedberg66593582014-07-09 12:59:14 +03006379 device_removed(sk, hdev, &cp->addr.bdaddr,
6380 cp->addr.type);
6381 goto complete;
6382 }
6383
Johan Hedberg85813a72015-10-21 18:02:59 +03006384 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006385
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006386 /* Kernel internally uses conn_params with resolvable private
6387 * address, but Remove Device allows only identity addresses.
6388 * Make sure it is enforced before calling
6389 * hci_conn_params_lookup.
6390 */
6391 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006392 err = mgmt_cmd_complete(sk, hdev->id,
6393 MGMT_OP_REMOVE_DEVICE,
6394 MGMT_STATUS_INVALID_PARAMS,
6395 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006396 goto unlock;
6397 }
6398
Johan Hedbergc71593d2014-07-02 17:37:28 +03006399 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6400 addr_type);
6401 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006402 err = mgmt_cmd_complete(sk, hdev->id,
6403 MGMT_OP_REMOVE_DEVICE,
6404 MGMT_STATUS_INVALID_PARAMS,
6405 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006406 goto unlock;
6407 }
6408
Johan Hedberg679d2b62015-10-16 10:07:52 +03006409 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6410 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006411 err = mgmt_cmd_complete(sk, hdev->id,
6412 MGMT_OP_REMOVE_DEVICE,
6413 MGMT_STATUS_INVALID_PARAMS,
6414 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006415 goto unlock;
6416 }
6417
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006418 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006419 list_del(&params->list);
6420 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006421 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006422
6423 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006424 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006425 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006426 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006427
Marcel Holtmann2faade52014-06-29 19:44:03 +02006428 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006429 err = mgmt_cmd_complete(sk, hdev->id,
6430 MGMT_OP_REMOVE_DEVICE,
6431 MGMT_STATUS_INVALID_PARAMS,
6432 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006433 goto unlock;
6434 }
6435
Johan Hedberg66593582014-07-09 12:59:14 +03006436 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6437 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6438 list_del(&b->list);
6439 kfree(b);
6440 }
6441
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006442 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006443
Johan Hedberg19de0822014-07-06 13:06:51 +03006444 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6445 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6446 continue;
6447 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006448 if (p->explicit_connect) {
6449 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6450 continue;
6451 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006452 list_del(&p->action);
6453 list_del(&p->list);
6454 kfree(p);
6455 }
6456
Marcel Holtmann181d6952020-05-06 09:57:47 +02006457 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006458
Johan Hedberg51d7a942015-11-11 08:11:18 +02006459 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006460 }
6461
Johan Hedberg66593582014-07-09 12:59:14 +03006462complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006463 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6464 MGMT_STATUS_SUCCESS, &cp->addr,
6465 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006466unlock:
6467 hci_dev_unlock(hdev);
6468 return err;
6469}
6470
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006471static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6472 u16 len)
6473{
6474 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006475 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6476 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006477 u16 param_count, expected_len;
6478 int i;
6479
6480 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006481 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6482 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006483
6484 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006485 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006486 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6487 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006488 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6489 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006490 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006491
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006492 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006493 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006494 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6495 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006496 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6497 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006498 }
6499
Marcel Holtmann181d6952020-05-06 09:57:47 +02006500 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006501
6502 hci_dev_lock(hdev);
6503
6504 hci_conn_params_clear_disabled(hdev);
6505
6506 for (i = 0; i < param_count; i++) {
6507 struct mgmt_conn_param *param = &cp->params[i];
6508 struct hci_conn_params *hci_param;
6509 u16 min, max, latency, timeout;
6510 u8 addr_type;
6511
Marcel Holtmann181d6952020-05-06 09:57:47 +02006512 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6513 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006514
6515 if (param->addr.type == BDADDR_LE_PUBLIC) {
6516 addr_type = ADDR_LE_DEV_PUBLIC;
6517 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6518 addr_type = ADDR_LE_DEV_RANDOM;
6519 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006520 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006521 continue;
6522 }
6523
6524 min = le16_to_cpu(param->min_interval);
6525 max = le16_to_cpu(param->max_interval);
6526 latency = le16_to_cpu(param->latency);
6527 timeout = le16_to_cpu(param->timeout);
6528
Marcel Holtmann181d6952020-05-06 09:57:47 +02006529 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6530 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006531
6532 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006533 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006534 continue;
6535 }
6536
6537 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6538 addr_type);
6539 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006540 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006541 continue;
6542 }
6543
6544 hci_param->conn_min_interval = min;
6545 hci_param->conn_max_interval = max;
6546 hci_param->conn_latency = latency;
6547 hci_param->supervision_timeout = timeout;
6548 }
6549
6550 hci_dev_unlock(hdev);
6551
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006552 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6553 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006554}
6555
Marcel Holtmanndbece372014-07-04 18:11:55 +02006556static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6557 void *data, u16 len)
6558{
6559 struct mgmt_cp_set_external_config *cp = data;
6560 bool changed;
6561 int err;
6562
Marcel Holtmann181d6952020-05-06 09:57:47 +02006563 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006564
6565 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6567 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006568
6569 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006570 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6571 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006572
6573 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006574 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6575 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006576
6577 hci_dev_lock(hdev);
6578
6579 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006580 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006581 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006582 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006583
6584 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6585 if (err < 0)
6586 goto unlock;
6587
6588 if (!changed)
6589 goto unlock;
6590
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006591 err = new_options(hdev, sk);
6592
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006593 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006594 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006595
Marcel Holtmann516018a2015-03-13 02:11:04 -07006596 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006597 hci_dev_set_flag(hdev, HCI_CONFIG);
6598 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006599
6600 queue_work(hdev->req_workqueue, &hdev->power_on);
6601 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006602 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006603 mgmt_index_added(hdev);
6604 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006605 }
6606
6607unlock:
6608 hci_dev_unlock(hdev);
6609 return err;
6610}
6611
Marcel Holtmann9713c172014-07-06 12:11:15 +02006612static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6613 void *data, u16 len)
6614{
6615 struct mgmt_cp_set_public_address *cp = data;
6616 bool changed;
6617 int err;
6618
Marcel Holtmann181d6952020-05-06 09:57:47 +02006619 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006620
6621 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006622 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6623 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006624
6625 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6627 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006628
6629 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006630 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6631 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006632
6633 hci_dev_lock(hdev);
6634
6635 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6636 bacpy(&hdev->public_addr, &cp->bdaddr);
6637
6638 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6639 if (err < 0)
6640 goto unlock;
6641
6642 if (!changed)
6643 goto unlock;
6644
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006645 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006646 err = new_options(hdev, sk);
6647
6648 if (is_configured(hdev)) {
6649 mgmt_index_removed(hdev);
6650
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006651 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006652
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006653 hci_dev_set_flag(hdev, HCI_CONFIG);
6654 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006655
6656 queue_work(hdev->req_workqueue, &hdev->power_on);
6657 }
6658
6659unlock:
6660 hci_dev_unlock(hdev);
6661 return err;
6662}
6663
Johan Hedberg40f66c02015-04-07 21:52:22 +03006664static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6665 u16 opcode, struct sk_buff *skb)
6666{
6667 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6668 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6669 u8 *h192, *r192, *h256, *r256;
6670 struct mgmt_pending_cmd *cmd;
6671 u16 eir_len;
6672 int err;
6673
Marcel Holtmann181d6952020-05-06 09:57:47 +02006674 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006675
6676 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6677 if (!cmd)
6678 return;
6679
6680 mgmt_cp = cmd->param;
6681
6682 if (status) {
6683 status = mgmt_status(status);
6684 eir_len = 0;
6685
6686 h192 = NULL;
6687 r192 = NULL;
6688 h256 = NULL;
6689 r256 = NULL;
6690 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6691 struct hci_rp_read_local_oob_data *rp;
6692
6693 if (skb->len != sizeof(*rp)) {
6694 status = MGMT_STATUS_FAILED;
6695 eir_len = 0;
6696 } else {
6697 status = MGMT_STATUS_SUCCESS;
6698 rp = (void *)skb->data;
6699
6700 eir_len = 5 + 18 + 18;
6701 h192 = rp->hash;
6702 r192 = rp->rand;
6703 h256 = NULL;
6704 r256 = NULL;
6705 }
6706 } else {
6707 struct hci_rp_read_local_oob_ext_data *rp;
6708
6709 if (skb->len != sizeof(*rp)) {
6710 status = MGMT_STATUS_FAILED;
6711 eir_len = 0;
6712 } else {
6713 status = MGMT_STATUS_SUCCESS;
6714 rp = (void *)skb->data;
6715
6716 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6717 eir_len = 5 + 18 + 18;
6718 h192 = NULL;
6719 r192 = NULL;
6720 } else {
6721 eir_len = 5 + 18 + 18 + 18 + 18;
6722 h192 = rp->hash192;
6723 r192 = rp->rand192;
6724 }
6725
6726 h256 = rp->hash256;
6727 r256 = rp->rand256;
6728 }
6729 }
6730
6731 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6732 if (!mgmt_rp)
6733 goto done;
6734
6735 if (status)
6736 goto send_rsp;
6737
6738 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6739 hdev->dev_class, 3);
6740
6741 if (h192 && r192) {
6742 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6743 EIR_SSP_HASH_C192, h192, 16);
6744 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6745 EIR_SSP_RAND_R192, r192, 16);
6746 }
6747
6748 if (h256 && r256) {
6749 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6750 EIR_SSP_HASH_C256, h256, 16);
6751 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6752 EIR_SSP_RAND_R256, r256, 16);
6753 }
6754
6755send_rsp:
6756 mgmt_rp->type = mgmt_cp->type;
6757 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6758
6759 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6760 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6761 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6762 if (err < 0 || status)
6763 goto done;
6764
6765 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6766
6767 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6768 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6769 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6770done:
6771 kfree(mgmt_rp);
6772 mgmt_pending_remove(cmd);
6773}
6774
6775static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6776 struct mgmt_cp_read_local_oob_ext_data *cp)
6777{
6778 struct mgmt_pending_cmd *cmd;
6779 struct hci_request req;
6780 int err;
6781
6782 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6783 cp, sizeof(*cp));
6784 if (!cmd)
6785 return -ENOMEM;
6786
6787 hci_req_init(&req, hdev);
6788
6789 if (bredr_sc_enabled(hdev))
6790 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6791 else
6792 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6793
6794 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6795 if (err < 0) {
6796 mgmt_pending_remove(cmd);
6797 return err;
6798 }
6799
6800 return 0;
6801}
6802
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006803static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6804 void *data, u16 data_len)
6805{
6806 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6807 struct mgmt_rp_read_local_oob_ext_data *rp;
6808 size_t rp_len;
6809 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006810 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006811 int err;
6812
Marcel Holtmann181d6952020-05-06 09:57:47 +02006813 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006814
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006815 if (hdev_is_powered(hdev)) {
6816 switch (cp->type) {
6817 case BIT(BDADDR_BREDR):
6818 status = mgmt_bredr_support(hdev);
6819 if (status)
6820 eir_len = 0;
6821 else
6822 eir_len = 5;
6823 break;
6824 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6825 status = mgmt_le_support(hdev);
6826 if (status)
6827 eir_len = 0;
6828 else
6829 eir_len = 9 + 3 + 18 + 18 + 3;
6830 break;
6831 default:
6832 status = MGMT_STATUS_INVALID_PARAMS;
6833 eir_len = 0;
6834 break;
6835 }
6836 } else {
6837 status = MGMT_STATUS_NOT_POWERED;
6838 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006839 }
6840
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006841 rp_len = sizeof(*rp) + eir_len;
6842 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006843 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006844 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006845
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006846 if (status)
6847 goto complete;
6848
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006849 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006850
6851 eir_len = 0;
6852 switch (cp->type) {
6853 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006854 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6855 err = read_local_ssp_oob_req(hdev, sk, cp);
6856 hci_dev_unlock(hdev);
6857 if (!err)
6858 goto done;
6859
6860 status = MGMT_STATUS_FAILED;
6861 goto complete;
6862 } else {
6863 eir_len = eir_append_data(rp->eir, eir_len,
6864 EIR_CLASS_OF_DEV,
6865 hdev->dev_class, 3);
6866 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006867 break;
6868 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006869 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6870 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006871 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006872 status = MGMT_STATUS_FAILED;
6873 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006874 }
6875
Marcel Holtmanne2135682015-04-02 12:00:58 -07006876 /* This should return the active RPA, but since the RPA
6877 * is only programmed on demand, it is really hard to fill
6878 * this in at the moment. For now disallow retrieving
6879 * local out-of-band data when privacy is in use.
6880 *
6881 * Returning the identity address will not help here since
6882 * pairing happens before the identity resolving key is
6883 * known and thus the connection establishment happens
6884 * based on the RPA and not the identity address.
6885 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006886 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006887 hci_dev_unlock(hdev);
6888 status = MGMT_STATUS_REJECTED;
6889 goto complete;
6890 }
6891
6892 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6893 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6894 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6895 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006896 memcpy(addr, &hdev->static_addr, 6);
6897 addr[6] = 0x01;
6898 } else {
6899 memcpy(addr, &hdev->bdaddr, 6);
6900 addr[6] = 0x00;
6901 }
6902
6903 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6904 addr, sizeof(addr));
6905
6906 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6907 role = 0x02;
6908 else
6909 role = 0x01;
6910
6911 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6912 &role, sizeof(role));
6913
Marcel Holtmann5082a592015-03-16 12:39:00 -07006914 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6915 eir_len = eir_append_data(rp->eir, eir_len,
6916 EIR_LE_SC_CONFIRM,
6917 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006918
Marcel Holtmann5082a592015-03-16 12:39:00 -07006919 eir_len = eir_append_data(rp->eir, eir_len,
6920 EIR_LE_SC_RANDOM,
6921 rand, sizeof(rand));
6922 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006923
Johan Hedbergf2252572015-11-18 12:49:20 +02006924 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006925
6926 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6927 flags |= LE_AD_NO_BREDR;
6928
6929 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6930 &flags, sizeof(flags));
6931 break;
6932 }
6933
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006934 hci_dev_unlock(hdev);
6935
Marcel Holtmann72000df2015-03-16 16:11:21 -07006936 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6937
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006938 status = MGMT_STATUS_SUCCESS;
6939
6940complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006941 rp->type = cp->type;
6942 rp->eir_len = cpu_to_le16(eir_len);
6943
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006944 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006945 status, rp, sizeof(*rp) + eir_len);
6946 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006947 goto done;
6948
6949 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6950 rp, sizeof(*rp) + eir_len,
6951 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006952
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006953done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006954 kfree(rp);
6955
6956 return err;
6957}
6958
Arman Uguray089fa8c2015-03-25 18:53:45 -07006959static u32 get_supported_adv_flags(struct hci_dev *hdev)
6960{
6961 u32 flags = 0;
6962
6963 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6964 flags |= MGMT_ADV_FLAG_DISCOV;
6965 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6966 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006967 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006968 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006969
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306970 /* In extended adv TX_POWER returned from Set Adv Param
6971 * will be always valid.
6972 */
6973 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6974 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006975 flags |= MGMT_ADV_FLAG_TX_POWER;
6976
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306977 if (ext_adv_capable(hdev)) {
6978 flags |= MGMT_ADV_FLAG_SEC_1M;
6979
6980 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6981 flags |= MGMT_ADV_FLAG_SEC_2M;
6982
6983 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6984 flags |= MGMT_ADV_FLAG_SEC_CODED;
6985 }
6986
Arman Uguray089fa8c2015-03-25 18:53:45 -07006987 return flags;
6988}
6989
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006990static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6991 void *data, u16 data_len)
6992{
6993 struct mgmt_rp_read_adv_features *rp;
6994 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006995 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006996 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006997 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006998 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006999
Marcel Holtmann181d6952020-05-06 09:57:47 +02007000 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007001
Arman Uguray089fa8c2015-03-25 18:53:45 -07007002 if (!lmp_le_capable(hdev))
7003 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7004 MGMT_STATUS_REJECTED);
7005
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007006 hci_dev_lock(hdev);
7007
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007008 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007009 rp = kmalloc(rp_len, GFP_ATOMIC);
7010 if (!rp) {
7011 hci_dev_unlock(hdev);
7012 return -ENOMEM;
7013 }
7014
Arman Uguray089fa8c2015-03-25 18:53:45 -07007015 supported_flags = get_supported_adv_flags(hdev);
7016
7017 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007018 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7019 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02007020 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007021 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007022
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007023 instance = rp->instance;
7024 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7025 *instance = adv_instance->instance;
7026 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007027 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007028
7029 hci_dev_unlock(hdev);
7030
7031 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7032 MGMT_STATUS_SUCCESS, rp, rp_len);
7033
7034 kfree(rp);
7035
7036 return err;
7037}
7038
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007039static u8 calculate_name_len(struct hci_dev *hdev)
7040{
7041 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7042
7043 return append_local_name(hdev, buf, 0);
7044}
7045
7046static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7047 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007048{
Arman Uguray4117ed72015-03-23 15:57:14 -07007049 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007050
Marcel Holtmann31a32482015-11-19 16:16:42 +01007051 if (is_adv_data) {
7052 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7053 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007054 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007055 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007056
Szymon Janc2bb368702016-09-18 12:50:05 +02007057 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007058 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007059 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007060 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007061 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007062
Szymon Janc2bb368702016-09-18 12:50:05 +02007063 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007064 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007065 }
7066
Szymon Janc2bb368702016-09-18 12:50:05 +02007067 return max_len;
7068}
7069
7070static bool flags_managed(u32 adv_flags)
7071{
7072 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7073 MGMT_ADV_FLAG_LIMITED_DISCOV |
7074 MGMT_ADV_FLAG_MANAGED_FLAGS);
7075}
7076
7077static bool tx_power_managed(u32 adv_flags)
7078{
7079 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7080}
7081
7082static bool name_managed(u32 adv_flags)
7083{
7084 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7085}
7086
7087static bool appearance_managed(u32 adv_flags)
7088{
7089 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7090}
7091
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007092static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7093 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007094{
7095 int i, cur_len;
7096 u8 max_len;
7097
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007098 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007099
Arman Uguray4117ed72015-03-23 15:57:14 -07007100 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007101 return false;
7102
Arman Uguray4117ed72015-03-23 15:57:14 -07007103 /* Make sure that the data is correctly formatted. */
7104 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7105 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007106
Szymon Janc9c9db782016-09-18 12:50:06 +02007107 if (data[i + 1] == EIR_FLAGS &&
7108 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007109 return false;
7110
Szymon Janc2bb368702016-09-18 12:50:05 +02007111 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7112 return false;
7113
7114 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7115 return false;
7116
7117 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7118 return false;
7119
7120 if (data[i + 1] == EIR_APPEARANCE &&
7121 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007122 return false;
7123
Arman Uguray24b4f382015-03-23 15:57:12 -07007124 /* If the current field length would exceed the total data
7125 * length, then it's invalid.
7126 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007127 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007128 return false;
7129 }
7130
7131 return true;
7132}
7133
Arman Uguray24b4f382015-03-23 15:57:12 -07007134static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7135 u16 opcode)
7136{
7137 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007138 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007139 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007140 struct adv_info *adv_instance, *n;
7141 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007142
Marcel Holtmann181d6952020-05-06 09:57:47 +02007143 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007144
7145 hci_dev_lock(hdev);
7146
7147 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7148
Florian Grandelfffd38b2015-06-18 03:16:47 +02007149 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7150 if (!adv_instance->pending)
7151 continue;
7152
7153 if (!status) {
7154 adv_instance->pending = false;
7155 continue;
7156 }
7157
7158 instance = adv_instance->instance;
7159
7160 if (hdev->cur_adv_instance == instance)
7161 cancel_adv_timeout(hdev);
7162
7163 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007164 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007165 }
7166
7167 if (!cmd)
7168 goto unlock;
7169
Florian Grandelfffd38b2015-06-18 03:16:47 +02007170 cp = cmd->param;
7171 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007172
7173 if (status)
7174 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7175 mgmt_status(status));
7176 else
7177 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7178 mgmt_status(status), &rp, sizeof(rp));
7179
7180 mgmt_pending_remove(cmd);
7181
7182unlock:
7183 hci_dev_unlock(hdev);
7184}
7185
7186static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7187 void *data, u16 data_len)
7188{
7189 struct mgmt_cp_add_advertising *cp = data;
7190 struct mgmt_rp_add_advertising rp;
7191 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307192 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007193 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007194 u16 timeout, duration;
7195 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7196 u8 schedule_instance = 0;
7197 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007198 int err;
7199 struct mgmt_pending_cmd *cmd;
7200 struct hci_request req;
7201
Marcel Holtmann181d6952020-05-06 09:57:47 +02007202 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007203
7204 status = mgmt_le_support(hdev);
7205 if (status)
7206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7207 status);
7208
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007209 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7210 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7211 MGMT_STATUS_INVALID_PARAMS);
7212
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007213 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7214 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7215 MGMT_STATUS_INVALID_PARAMS);
7216
Arman Uguray24b4f382015-03-23 15:57:12 -07007217 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007218 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007219 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007220
Florian Grandelfffd38b2015-06-18 03:16:47 +02007221 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307222 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007223 */
7224 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307225 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7226 if (flags & ~supported_flags ||
7227 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007228 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7229 MGMT_STATUS_INVALID_PARAMS);
7230
7231 hci_dev_lock(hdev);
7232
Arman Uguray912098a2015-03-23 15:57:15 -07007233 if (timeout && !hdev_is_powered(hdev)) {
7234 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7235 MGMT_STATUS_REJECTED);
7236 goto unlock;
7237 }
7238
Arman Uguray24b4f382015-03-23 15:57:12 -07007239 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007240 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007241 pending_find(MGMT_OP_SET_LE, hdev)) {
7242 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7243 MGMT_STATUS_BUSY);
7244 goto unlock;
7245 }
7246
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007247 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7248 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007249 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007250 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7251 MGMT_STATUS_INVALID_PARAMS);
7252 goto unlock;
7253 }
7254
Florian Grandelfffd38b2015-06-18 03:16:47 +02007255 err = hci_add_adv_instance(hdev, cp->instance, flags,
7256 cp->adv_data_len, cp->data,
7257 cp->scan_rsp_len,
7258 cp->data + cp->adv_data_len,
7259 timeout, duration);
7260 if (err < 0) {
7261 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7262 MGMT_STATUS_FAILED);
7263 goto unlock;
7264 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007265
Florian Grandelfffd38b2015-06-18 03:16:47 +02007266 /* Only trigger an advertising added event if a new instance was
7267 * actually added.
7268 */
7269 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007270 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007271
Florian Grandelfffd38b2015-06-18 03:16:47 +02007272 if (hdev->cur_adv_instance == cp->instance) {
7273 /* If the currently advertised instance is being changed then
7274 * cancel the current advertising and schedule the next
7275 * instance. If there is only one instance then the overridden
7276 * advertising data will be visible right away.
7277 */
7278 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007279
Florian Grandelfffd38b2015-06-18 03:16:47 +02007280 next_instance = hci_get_next_instance(hdev, cp->instance);
7281 if (next_instance)
7282 schedule_instance = next_instance->instance;
7283 } else if (!hdev->adv_instance_timeout) {
7284 /* Immediately advertise the new instance if no other
7285 * instance is currently being advertised.
7286 */
7287 schedule_instance = cp->instance;
7288 }
Arman Uguray912098a2015-03-23 15:57:15 -07007289
Florian Grandelfffd38b2015-06-18 03:16:47 +02007290 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7291 * there is no instance to be advertised then we have no HCI
7292 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007293 */
7294 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007295 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7296 !schedule_instance) {
7297 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007298 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7299 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7300 goto unlock;
7301 }
7302
7303 /* We're good to go, update advertising data, parameters, and start
7304 * advertising.
7305 */
7306 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7307 data_len);
7308 if (!cmd) {
7309 err = -ENOMEM;
7310 goto unlock;
7311 }
7312
7313 hci_req_init(&req, hdev);
7314
Johan Hedbergf2252572015-11-18 12:49:20 +02007315 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007316
Florian Grandelfffd38b2015-06-18 03:16:47 +02007317 if (!err)
7318 err = hci_req_run(&req, add_advertising_complete);
7319
Joseph Hwang72da7b22020-03-10 09:31:50 -07007320 if (err < 0) {
7321 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7322 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007323 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007324 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007325
7326unlock:
7327 hci_dev_unlock(hdev);
7328
7329 return err;
7330}
7331
Arman Ugurayda9293352015-03-23 15:57:13 -07007332static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7333 u16 opcode)
7334{
7335 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007336 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007337 struct mgmt_rp_remove_advertising rp;
7338
Marcel Holtmann181d6952020-05-06 09:57:47 +02007339 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007340
7341 hci_dev_lock(hdev);
7342
7343 /* A failure status here only means that we failed to disable
7344 * advertising. Otherwise, the advertising instance has been removed,
7345 * so report success.
7346 */
7347 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7348 if (!cmd)
7349 goto unlock;
7350
Florian Grandel01948332015-06-18 03:16:48 +02007351 cp = cmd->param;
7352 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007353
7354 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7355 &rp, sizeof(rp));
7356 mgmt_pending_remove(cmd);
7357
7358unlock:
7359 hci_dev_unlock(hdev);
7360}
7361
7362static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7363 void *data, u16 data_len)
7364{
7365 struct mgmt_cp_remove_advertising *cp = data;
7366 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007367 struct mgmt_pending_cmd *cmd;
7368 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007369 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007370
Marcel Holtmann181d6952020-05-06 09:57:47 +02007371 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007372
Arman Ugurayda9293352015-03-23 15:57:13 -07007373 hci_dev_lock(hdev);
7374
Johan Hedberg952497b2015-06-18 21:05:31 +03007375 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007376 err = mgmt_cmd_status(sk, hdev->id,
7377 MGMT_OP_REMOVE_ADVERTISING,
7378 MGMT_STATUS_INVALID_PARAMS);
7379 goto unlock;
7380 }
7381
Arman Ugurayda9293352015-03-23 15:57:13 -07007382 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7383 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7384 pending_find(MGMT_OP_SET_LE, hdev)) {
7385 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7386 MGMT_STATUS_BUSY);
7387 goto unlock;
7388 }
7389
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007390 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007391 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7392 MGMT_STATUS_INVALID_PARAMS);
7393 goto unlock;
7394 }
7395
Florian Grandel01948332015-06-18 03:16:48 +02007396 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007397
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007398 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007399
Florian Grandel01948332015-06-18 03:16:48 +02007400 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007401 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007402
Florian Grandel01948332015-06-18 03:16:48 +02007403 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7404 * flag is set or the device isn't powered then we have no HCI
7405 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007406 */
Florian Grandel01948332015-06-18 03:16:48 +02007407 if (skb_queue_empty(&req.cmd_q) ||
7408 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007409 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307410 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007411 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007412 err = mgmt_cmd_complete(sk, hdev->id,
7413 MGMT_OP_REMOVE_ADVERTISING,
7414 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7415 goto unlock;
7416 }
7417
7418 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7419 data_len);
7420 if (!cmd) {
7421 err = -ENOMEM;
7422 goto unlock;
7423 }
7424
Arman Ugurayda9293352015-03-23 15:57:13 -07007425 err = hci_req_run(&req, remove_advertising_complete);
7426 if (err < 0)
7427 mgmt_pending_remove(cmd);
7428
7429unlock:
7430 hci_dev_unlock(hdev);
7431
7432 return err;
7433}
7434
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007435static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7436 void *data, u16 data_len)
7437{
7438 struct mgmt_cp_get_adv_size_info *cp = data;
7439 struct mgmt_rp_get_adv_size_info rp;
7440 u32 flags, supported_flags;
7441 int err;
7442
Marcel Holtmann181d6952020-05-06 09:57:47 +02007443 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007444
7445 if (!lmp_le_capable(hdev))
7446 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7447 MGMT_STATUS_REJECTED);
7448
7449 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7451 MGMT_STATUS_INVALID_PARAMS);
7452
7453 flags = __le32_to_cpu(cp->flags);
7454
7455 /* The current implementation only supports a subset of the specified
7456 * flags.
7457 */
7458 supported_flags = get_supported_adv_flags(hdev);
7459 if (flags & ~supported_flags)
7460 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7461 MGMT_STATUS_INVALID_PARAMS);
7462
7463 rp.instance = cp->instance;
7464 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007465 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7466 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007467
7468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7469 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7470
7471 return err;
7472}
7473
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007474static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007475 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007476 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007477 HCI_MGMT_NO_HDEV |
7478 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007479 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007480 HCI_MGMT_NO_HDEV |
7481 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007482 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007483 HCI_MGMT_NO_HDEV |
7484 HCI_MGMT_UNTRUSTED },
7485 { read_controller_info, MGMT_READ_INFO_SIZE,
7486 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007487 { set_powered, MGMT_SETTING_SIZE },
7488 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7489 { set_connectable, MGMT_SETTING_SIZE },
7490 { set_fast_connectable, MGMT_SETTING_SIZE },
7491 { set_bondable, MGMT_SETTING_SIZE },
7492 { set_link_security, MGMT_SETTING_SIZE },
7493 { set_ssp, MGMT_SETTING_SIZE },
7494 { set_hs, MGMT_SETTING_SIZE },
7495 { set_le, MGMT_SETTING_SIZE },
7496 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7497 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7498 { add_uuid, MGMT_ADD_UUID_SIZE },
7499 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007500 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7501 HCI_MGMT_VAR_LEN },
7502 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7503 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007504 { disconnect, MGMT_DISCONNECT_SIZE },
7505 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7506 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7507 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7508 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7509 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7510 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7511 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7512 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7513 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7514 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7515 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007516 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7517 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7518 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007519 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7520 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7521 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7522 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7523 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7524 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7525 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7526 { set_advertising, MGMT_SETTING_SIZE },
7527 { set_bredr, MGMT_SETTING_SIZE },
7528 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7529 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7530 { set_secure_conn, MGMT_SETTING_SIZE },
7531 { set_debug_keys, MGMT_SETTING_SIZE },
7532 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007533 { load_irks, MGMT_LOAD_IRKS_SIZE,
7534 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007535 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7536 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7537 { add_device, MGMT_ADD_DEVICE_SIZE },
7538 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007539 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7540 HCI_MGMT_VAR_LEN },
7541 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007542 HCI_MGMT_NO_HDEV |
7543 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007544 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007545 HCI_MGMT_UNCONFIGURED |
7546 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007547 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7548 HCI_MGMT_UNCONFIGURED },
7549 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7550 HCI_MGMT_UNCONFIGURED },
7551 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7552 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007553 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007554 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007555 HCI_MGMT_NO_HDEV |
7556 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007557 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007558 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7559 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007560 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007561 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007562 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007563 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7564 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007565 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307566 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307567 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007568 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7569 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007570 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007571 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7572 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007573 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7574 HCI_MGMT_UNTRUSTED |
7575 HCI_MGMT_HDEV_OPTIONAL },
7576 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7577 HCI_MGMT_VAR_LEN |
7578 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007579 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7580 HCI_MGMT_UNTRUSTED },
7581 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7582 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007583 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7584 HCI_MGMT_UNTRUSTED },
7585 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7586 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007587 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7588 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007589 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02007590 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
7591 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007592};
7593
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007594void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007595{
Marcel Holtmannced85542015-03-14 19:27:56 -07007596 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007597
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007598 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7599 return;
7600
Marcel Holtmannf9207332015-03-14 19:27:55 -07007601 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007602 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007603 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7604 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7605 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007606 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007607 } else {
7608 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7609 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007610 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007611 }
7612 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007613 case HCI_AMP:
7614 ev.type = 0x02;
7615 break;
7616 default:
7617 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007618 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007619
7620 ev.bus = hdev->bus;
7621
7622 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7623 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007624}
7625
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007626void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007627{
Marcel Holtmannced85542015-03-14 19:27:56 -07007628 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007629 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007630
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007631 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7632 return;
7633
Marcel Holtmannf9207332015-03-14 19:27:55 -07007634 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007635 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007636 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007637
Marcel Holtmannf9207332015-03-14 19:27:55 -07007638 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7639 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7640 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007641 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007642 } else {
7643 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7644 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007645 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007646 }
7647 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007648 case HCI_AMP:
7649 ev.type = 0x02;
7650 break;
7651 default:
7652 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007653 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007654
7655 ev.bus = hdev->bus;
7656
7657 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7658 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007659}
7660
Andre Guedes6046dc32014-02-26 20:21:51 -03007661/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007662static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007663{
7664 struct hci_conn_params *p;
7665
7666 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007667 /* Needed for AUTO_OFF case where might not "really"
7668 * have been powered off.
7669 */
7670 list_del_init(&p->action);
7671
7672 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007673 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007674 case HCI_AUTO_CONN_ALWAYS:
7675 list_add(&p->action, &hdev->pend_le_conns);
7676 break;
7677 case HCI_AUTO_CONN_REPORT:
7678 list_add(&p->action, &hdev->pend_le_reports);
7679 break;
7680 default:
7681 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007682 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007683 }
7684}
7685
Johan Hedberg2ff13892015-11-25 16:15:44 +02007686void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007687{
7688 struct cmd_lookup match = { NULL, hdev };
7689
Marcel Holtmann181d6952020-05-06 09:57:47 +02007690 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007691
Johan Hedberg2ff13892015-11-25 16:15:44 +02007692 hci_dev_lock(hdev);
7693
7694 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007695 restart_le_actions(hdev);
7696 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007697 }
7698
Johan Hedberg229ab392013-03-15 17:06:53 -05007699 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7700
7701 new_settings(hdev, match.sk);
7702
Johan Hedberg229ab392013-03-15 17:06:53 -05007703 if (match.sk)
7704 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007705
7706 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007707}
7708
Johan Hedberg2ff13892015-11-25 16:15:44 +02007709void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007710{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007711 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007712 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007713
Johan Hedberg229ab392013-03-15 17:06:53 -05007714 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007715
7716 /* If the power off is because of hdev unregistration let
7717 * use the appropriate INVALID_INDEX status. Otherwise use
7718 * NOT_POWERED. We cover both scenarios here since later in
7719 * mgmt_index_removed() any hci_conn callbacks will have already
7720 * been triggered, potentially causing misleading DISCONNECTED
7721 * status responses.
7722 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007723 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007724 status = MGMT_STATUS_INVALID_INDEX;
7725 else
7726 status = MGMT_STATUS_NOT_POWERED;
7727
7728 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007729
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007730 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007731 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7732 zero_cod, sizeof(zero_cod),
7733 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007734 ext_info_changed(hdev, NULL);
7735 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007736
Johan Hedberg2ff13892015-11-25 16:15:44 +02007737 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007738
7739 if (match.sk)
7740 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007741}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007742
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007743void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007744{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007745 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007746 u8 status;
7747
Johan Hedberg333ae952015-03-17 13:48:47 +02007748 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007749 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007750 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007751
7752 if (err == -ERFKILL)
7753 status = MGMT_STATUS_RFKILLED;
7754 else
7755 status = MGMT_STATUS_FAILED;
7756
Johan Hedberga69e8372015-03-06 21:08:53 +02007757 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007758
7759 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007760}
7761
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007762void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7763 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007764{
Johan Hedberg86742e12011-11-07 23:13:38 +02007765 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007766
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007767 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007768
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007769 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007770 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007771 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007772 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007773 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007774 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007775
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007776 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007777}
Johan Hedbergf7520542011-01-20 12:34:39 +02007778
Johan Hedbergd7b25452014-05-23 13:19:53 +03007779static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7780{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007781 switch (ltk->type) {
7782 case SMP_LTK:
7783 case SMP_LTK_SLAVE:
7784 if (ltk->authenticated)
7785 return MGMT_LTK_AUTHENTICATED;
7786 return MGMT_LTK_UNAUTHENTICATED;
7787 case SMP_LTK_P256:
7788 if (ltk->authenticated)
7789 return MGMT_LTK_P256_AUTH;
7790 return MGMT_LTK_P256_UNAUTH;
7791 case SMP_LTK_P256_DEBUG:
7792 return MGMT_LTK_P256_DEBUG;
7793 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007794
7795 return MGMT_LTK_UNAUTHENTICATED;
7796}
7797
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007798void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007799{
7800 struct mgmt_ev_new_long_term_key ev;
7801
7802 memset(&ev, 0, sizeof(ev));
7803
Marcel Holtmann5192d302014-02-19 17:11:58 -08007804 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007805 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007806 * to store long term keys. Their addresses will change the
7807 * next time around.
7808 *
7809 * Only when a remote device provides an identity address
7810 * make sure the long term key is stored. If the remote
7811 * identity is known, the long term keys are internally
7812 * mapped to the identity address. So allow static random
7813 * and public addresses here.
7814 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007815 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7816 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7817 ev.store_hint = 0x00;
7818 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007819 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007820
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007821 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007822 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007823 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007824 ev.key.enc_size = key->enc_size;
7825 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007826 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007827
Johan Hedberg2ceba532014-06-16 19:25:16 +03007828 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007829 ev.key.master = 1;
7830
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007831 /* Make sure we copy only the significant bytes based on the
7832 * encryption key size, and set the rest of the value to zeroes.
7833 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007834 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007835 memset(ev.key.val + key->enc_size, 0,
7836 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007837
Marcel Holtmann083368f2013-10-15 14:26:29 -07007838 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007839}
7840
Johan Hedbergcad20c22015-10-12 13:36:19 +02007841void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007842{
7843 struct mgmt_ev_new_irk ev;
7844
7845 memset(&ev, 0, sizeof(ev));
7846
Johan Hedbergcad20c22015-10-12 13:36:19 +02007847 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007848
Johan Hedberg95fbac82014-02-19 15:18:31 +02007849 bacpy(&ev.rpa, &irk->rpa);
7850 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7851 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7852 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7853
7854 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7855}
7856
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007857void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7858 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007859{
7860 struct mgmt_ev_new_csrk ev;
7861
7862 memset(&ev, 0, sizeof(ev));
7863
7864 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007865 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007866 * to store signature resolving keys. Their addresses will change
7867 * the next time around.
7868 *
7869 * Only when a remote device provides an identity address
7870 * make sure the signature resolving key is stored. So allow
7871 * static random and public addresses here.
7872 */
7873 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7874 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7875 ev.store_hint = 0x00;
7876 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007877 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007878
7879 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7880 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007881 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007882 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7883
7884 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7885}
7886
Andre Guedesffb5a8272014-07-01 18:10:11 -03007887void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007888 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7889 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007890{
7891 struct mgmt_ev_new_conn_param ev;
7892
Johan Hedbergc103aea2014-07-02 17:37:34 +03007893 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7894 return;
7895
Andre Guedesffb5a8272014-07-01 18:10:11 -03007896 memset(&ev, 0, sizeof(ev));
7897 bacpy(&ev.addr.bdaddr, bdaddr);
7898 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007899 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007900 ev.min_interval = cpu_to_le16(min_interval);
7901 ev.max_interval = cpu_to_le16(max_interval);
7902 ev.latency = cpu_to_le16(latency);
7903 ev.timeout = cpu_to_le16(timeout);
7904
7905 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7906}
7907
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007908void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7909 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007910{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007911 char buf[512];
7912 struct mgmt_ev_device_connected *ev = (void *) buf;
7913 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007914
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007915 bacpy(&ev->addr.bdaddr, &conn->dst);
7916 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007917
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007918 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007919
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007920 /* We must ensure that the EIR Data fields are ordered and
7921 * unique. Keep it simple for now and avoid the problem by not
7922 * adding any BR/EDR data to the LE adv.
7923 */
7924 if (conn->le_adv_data_len > 0) {
7925 memcpy(&ev->eir[eir_len],
7926 conn->le_adv_data, conn->le_adv_data_len);
7927 eir_len = conn->le_adv_data_len;
7928 } else {
7929 if (name_len > 0)
7930 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7931 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007932
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007933 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007934 eir_len = eir_append_data(ev->eir, eir_len,
7935 EIR_CLASS_OF_DEV,
7936 conn->dev_class, 3);
7937 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007938
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007939 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007940
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007941 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7942 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007943}
7944
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007945static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007946{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007947 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007948
Johan Hedbergf5818c22014-12-05 13:36:02 +02007949 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007950
7951 *sk = cmd->sk;
7952 sock_hold(*sk);
7953
Johan Hedberga664b5b2011-02-19 12:06:02 -03007954 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007955}
7956
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007957static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007958{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007959 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007960 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007961
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007962 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7963
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007964 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007965 mgmt_pending_remove(cmd);
7966}
7967
Johan Hedberg84c61d92014-08-01 11:13:30 +03007968bool mgmt_powering_down(struct hci_dev *hdev)
7969{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007970 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007971 struct mgmt_mode *cp;
7972
Johan Hedberg333ae952015-03-17 13:48:47 +02007973 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007974 if (!cmd)
7975 return false;
7976
7977 cp = cmd->param;
7978 if (!cp->val)
7979 return true;
7980
7981 return false;
7982}
7983
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007984void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007985 u8 link_type, u8 addr_type, u8 reason,
7986 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007987{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007988 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007989 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007990
Johan Hedberg84c61d92014-08-01 11:13:30 +03007991 /* The connection is still in hci_conn_hash so test for 1
7992 * instead of 0 to know if this is the last one.
7993 */
7994 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7995 cancel_delayed_work(&hdev->power_off);
7996 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007997 }
7998
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007999 if (!mgmt_connected)
8000 return;
8001
Andre Guedes57eb7762013-10-30 19:01:41 -03008002 if (link_type != ACL_LINK && link_type != LE_LINK)
8003 return;
8004
Johan Hedberg744cf192011-11-08 20:40:14 +02008005 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008006
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008007 bacpy(&ev.addr.bdaddr, bdaddr);
8008 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8009 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008010
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008011 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008012
8013 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008014 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008015
Johan Hedberg124f6e32012-02-09 13:50:12 +02008016 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008017 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008018}
8019
Marcel Holtmann78929242013-10-06 23:55:47 -07008020void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8021 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008022{
Andre Guedes3655bba2013-10-30 19:01:40 -03008023 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8024 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008025 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008026
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008027 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8028 hdev);
8029
Johan Hedberg333ae952015-03-17 13:48:47 +02008030 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008031 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008032 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008033
Andre Guedes3655bba2013-10-30 19:01:40 -03008034 cp = cmd->param;
8035
8036 if (bacmp(bdaddr, &cp->addr.bdaddr))
8037 return;
8038
8039 if (cp->addr.type != bdaddr_type)
8040 return;
8041
Johan Hedbergf5818c22014-12-05 13:36:02 +02008042 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008043 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008044}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008045
Marcel Holtmann445608d2013-10-06 23:55:48 -07008046void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8047 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008048{
8049 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008050
Johan Hedberg84c61d92014-08-01 11:13:30 +03008051 /* The connection is still in hci_conn_hash so test for 1
8052 * instead of 0 to know if this is the last one.
8053 */
8054 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8055 cancel_delayed_work(&hdev->power_off);
8056 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008057 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008058
Johan Hedberg4c659c32011-11-07 23:13:39 +02008059 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008060 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008061 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008062
Marcel Holtmann445608d2013-10-06 23:55:48 -07008063 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008064}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008065
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008066void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008067{
8068 struct mgmt_ev_pin_code_request ev;
8069
Johan Hedbergd8457692012-02-17 14:24:57 +02008070 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008071 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008072 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008073
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008074 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008075}
8076
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008077void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8078 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008079{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008080 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008081
Johan Hedberg333ae952015-03-17 13:48:47 +02008082 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008083 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008084 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008085
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008086 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008087 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008088}
8089
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008090void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8091 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008092{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008093 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008094
Johan Hedberg333ae952015-03-17 13:48:47 +02008095 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008096 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008097 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008098
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008099 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008100 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008101}
Johan Hedberga5c29682011-02-19 12:05:57 -03008102
Johan Hedberg744cf192011-11-08 20:40:14 +02008103int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008104 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008105 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008106{
8107 struct mgmt_ev_user_confirm_request ev;
8108
Marcel Holtmann181d6952020-05-06 09:57:47 +02008109 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008110
Johan Hedberg272d90d2012-02-09 15:26:12 +02008111 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008112 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008113 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008114 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008115
Johan Hedberg744cf192011-11-08 20:40:14 +02008116 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008117 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008118}
8119
Johan Hedberg272d90d2012-02-09 15:26:12 +02008120int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008121 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008122{
8123 struct mgmt_ev_user_passkey_request ev;
8124
Marcel Holtmann181d6952020-05-06 09:57:47 +02008125 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008126
Johan Hedberg272d90d2012-02-09 15:26:12 +02008127 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008128 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008129
8130 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008131 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008132}
8133
Brian Gix0df4c182011-11-16 13:53:13 -08008134static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008135 u8 link_type, u8 addr_type, u8 status,
8136 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008137{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008138 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008139
Johan Hedberg333ae952015-03-17 13:48:47 +02008140 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008141 if (!cmd)
8142 return -ENOENT;
8143
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008144 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008145 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008146
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008147 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008148}
8149
Johan Hedberg744cf192011-11-08 20:40:14 +02008150int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008151 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008152{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008153 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008154 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008155}
8156
Johan Hedberg272d90d2012-02-09 15:26:12 +02008157int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008158 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008159{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008160 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008161 status,
8162 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008163}
Johan Hedberg2a611692011-02-19 12:06:00 -03008164
Brian Gix604086b2011-11-23 08:28:33 -08008165int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008166 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008167{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008168 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008169 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008170}
8171
Johan Hedberg272d90d2012-02-09 15:26:12 +02008172int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008173 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008174{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008175 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008176 status,
8177 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008178}
8179
Johan Hedberg92a25252012-09-06 18:39:26 +03008180int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8181 u8 link_type, u8 addr_type, u32 passkey,
8182 u8 entered)
8183{
8184 struct mgmt_ev_passkey_notify ev;
8185
Marcel Holtmann181d6952020-05-06 09:57:47 +02008186 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008187
8188 bacpy(&ev.addr.bdaddr, bdaddr);
8189 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8190 ev.passkey = __cpu_to_le32(passkey);
8191 ev.entered = entered;
8192
8193 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8194}
8195
Johan Hedberge1e930f2014-09-08 17:09:49 -07008196void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008197{
8198 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008199 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008200 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008201
Johan Hedberge1e930f2014-09-08 17:09:49 -07008202 bacpy(&ev.addr.bdaddr, &conn->dst);
8203 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8204 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008205
Johan Hedberge1e930f2014-09-08 17:09:49 -07008206 cmd = find_pairing(conn);
8207
8208 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8209 cmd ? cmd->sk : NULL);
8210
Johan Hedberga511b352014-12-11 21:45:45 +02008211 if (cmd) {
8212 cmd->cmd_complete(cmd, status);
8213 mgmt_pending_remove(cmd);
8214 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008215}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008216
Marcel Holtmann464996a2013-10-15 14:26:24 -07008217void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008218{
8219 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008220 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008221
8222 if (status) {
8223 u8 mgmt_err = mgmt_status(status);
8224 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008225 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008226 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008227 }
8228
Marcel Holtmann464996a2013-10-15 14:26:24 -07008229 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008230 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008231 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008232 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008233
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008234 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008235 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008236
Johan Hedberg47990ea2012-02-22 11:58:37 +02008237 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008238 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008239
8240 if (match.sk)
8241 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008242}
8243
Johan Hedberg890ea892013-03-15 17:06:52 -05008244static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008245{
Johan Hedberg890ea892013-03-15 17:06:52 -05008246 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008247 struct hci_cp_write_eir cp;
8248
Johan Hedberg976eb202012-10-24 21:12:01 +03008249 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008250 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008251
Johan Hedbergc80da272012-02-22 15:38:48 +02008252 memset(hdev->eir, 0, sizeof(hdev->eir));
8253
Johan Hedbergcacaf522012-02-21 00:52:42 +02008254 memset(&cp, 0, sizeof(cp));
8255
Johan Hedberg890ea892013-03-15 17:06:52 -05008256 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008257}
8258
Marcel Holtmann3e248562013-10-15 14:26:25 -07008259void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008260{
8261 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008262 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008263 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008264
8265 if (status) {
8266 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008267
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008268 if (enable && hci_dev_test_and_clear_flag(hdev,
8269 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008270 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008271 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008272 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008273
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008274 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8275 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008276 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008277 }
8278
8279 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008280 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008281 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008282 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008283 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008284 changed = hci_dev_test_and_clear_flag(hdev,
8285 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008286 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008287 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008288 }
8289
8290 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8291
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008292 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008293 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008294
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008295 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008296 sock_put(match.sk);
8297
Johan Hedberg890ea892013-03-15 17:06:52 -05008298 hci_req_init(&req, hdev);
8299
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008300 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8301 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008302 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8303 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008304 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008305 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008306 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008307 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008308
8309 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008310}
8311
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008312static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008313{
8314 struct cmd_lookup *match = data;
8315
Johan Hedberg90e70452012-02-23 23:09:40 +02008316 if (match->sk == NULL) {
8317 match->sk = cmd->sk;
8318 sock_hold(match->sk);
8319 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008320}
8321
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008322void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8323 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008324{
Johan Hedberg90e70452012-02-23 23:09:40 +02008325 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008326
Johan Hedberg92da6092013-03-15 17:06:55 -05008327 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8328 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8329 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008330
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008331 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008332 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8333 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008334 ext_info_changed(hdev, NULL);
8335 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008336
8337 if (match.sk)
8338 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008339}
8340
Marcel Holtmann7667da32013-10-15 14:26:27 -07008341void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008342{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008343 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008344 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008345
Johan Hedberg13928972013-03-15 17:07:00 -05008346 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008347 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008348
8349 memset(&ev, 0, sizeof(ev));
8350 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008351 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008352
Johan Hedberg333ae952015-03-17 13:48:47 +02008353 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008354 if (!cmd) {
8355 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008356
Johan Hedberg13928972013-03-15 17:07:00 -05008357 /* If this is a HCI command related to powering on the
8358 * HCI dev don't send any mgmt signals.
8359 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008360 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008361 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008362 }
8363
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008364 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8365 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008366 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008367}
Szymon Jancc35938b2011-03-22 13:12:21 +01008368
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008369static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8370{
8371 int i;
8372
8373 for (i = 0; i < uuid_count; i++) {
8374 if (!memcmp(uuid, uuids[i], 16))
8375 return true;
8376 }
8377
8378 return false;
8379}
8380
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008381static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8382{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008383 u16 parsed = 0;
8384
8385 while (parsed < eir_len) {
8386 u8 field_len = eir[0];
8387 u8 uuid[16];
8388 int i;
8389
8390 if (field_len == 0)
8391 break;
8392
8393 if (eir_len - parsed < field_len + 1)
8394 break;
8395
8396 switch (eir[1]) {
8397 case EIR_UUID16_ALL:
8398 case EIR_UUID16_SOME:
8399 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008400 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008401 uuid[13] = eir[i + 3];
8402 uuid[12] = eir[i + 2];
8403 if (has_uuid(uuid, uuid_count, uuids))
8404 return true;
8405 }
8406 break;
8407 case EIR_UUID32_ALL:
8408 case EIR_UUID32_SOME:
8409 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008410 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008411 uuid[15] = eir[i + 5];
8412 uuid[14] = eir[i + 4];
8413 uuid[13] = eir[i + 3];
8414 uuid[12] = eir[i + 2];
8415 if (has_uuid(uuid, uuid_count, uuids))
8416 return true;
8417 }
8418 break;
8419 case EIR_UUID128_ALL:
8420 case EIR_UUID128_SOME:
8421 for (i = 0; i + 17 <= field_len; i += 16) {
8422 memcpy(uuid, eir + i + 2, 16);
8423 if (has_uuid(uuid, uuid_count, uuids))
8424 return true;
8425 }
8426 break;
8427 }
8428
8429 parsed += field_len + 1;
8430 eir += field_len + 1;
8431 }
8432
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008433 return false;
8434}
8435
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008436static void restart_le_scan(struct hci_dev *hdev)
8437{
8438 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008439 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008440 return;
8441
8442 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8443 hdev->discovery.scan_start +
8444 hdev->discovery.scan_duration))
8445 return;
8446
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008447 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008448 DISCOV_LE_RESTART_DELAY);
8449}
8450
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008451static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8452 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8453{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008454 /* If a RSSI threshold has been specified, and
8455 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8456 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8457 * is set, let it through for further processing, as we might need to
8458 * restart the scan.
8459 *
8460 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8461 * the results are also dropped.
8462 */
8463 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8464 (rssi == HCI_RSSI_INVALID ||
8465 (rssi < hdev->discovery.rssi &&
8466 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8467 return false;
8468
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008469 if (hdev->discovery.uuid_count != 0) {
8470 /* If a list of UUIDs is provided in filter, results with no
8471 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008472 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008473 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8474 hdev->discovery.uuids) &&
8475 !eir_has_uuids(scan_rsp, scan_rsp_len,
8476 hdev->discovery.uuid_count,
8477 hdev->discovery.uuids))
8478 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008479 }
8480
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008481 /* If duplicate filtering does not report RSSI changes, then restart
8482 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008483 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008484 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8485 restart_le_scan(hdev);
8486
8487 /* Validate RSSI value against the RSSI threshold once more. */
8488 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8489 rssi < hdev->discovery.rssi)
8490 return false;
8491 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008492
8493 return true;
8494}
8495
Marcel Holtmann901801b2013-10-06 23:55:51 -07008496void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008497 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8498 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008499{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008500 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008501 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008502 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008503
Johan Hedberg75ce2082014-07-02 22:42:01 +03008504 /* Don't send events for a non-kernel initiated discovery. With
8505 * LE one exception is if we have pend_le_reports > 0 in which
8506 * case we're doing passive scanning and want these events.
8507 */
8508 if (!hci_discovery_active(hdev)) {
8509 if (link_type == ACL_LINK)
8510 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03008511 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03008512 return;
8513 }
Andre Guedes12602d02013-04-30 15:29:40 -03008514
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008515 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008516 /* We are using service discovery */
8517 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8518 scan_rsp_len))
8519 return;
8520 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008521
Johan Hedberg78b781c2016-01-05 13:19:32 +02008522 if (hdev->discovery.limited) {
8523 /* Check for limited discoverable bit */
8524 if (dev_class) {
8525 if (!(dev_class[1] & 0x20))
8526 return;
8527 } else {
8528 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8529 if (!flags || !(flags[0] & LE_AD_LIMITED))
8530 return;
8531 }
8532 }
8533
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008534 /* Make sure that the buffer is big enough. The 5 extra bytes
8535 * are for the potential CoD field.
8536 */
8537 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008538 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008539
Johan Hedberg1dc06092012-01-15 21:01:23 +02008540 memset(buf, 0, sizeof(buf));
8541
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008542 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8543 * RSSI value was reported as 0 when not available. This behavior
8544 * is kept when using device discovery. This is required for full
8545 * backwards compatibility with the API.
8546 *
8547 * However when using service discovery, the value 127 will be
8548 * returned when the RSSI is not available.
8549 */
Szymon Janc91200e92015-01-22 16:57:05 +01008550 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8551 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008552 rssi = 0;
8553
Johan Hedberg841c5642014-07-07 12:45:54 +03008554 bacpy(&ev->addr.bdaddr, bdaddr);
8555 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008556 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008557 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008558
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008559 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008560 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008561 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008562
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008563 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8564 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008565 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008566 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008567
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008568 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008569 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008570 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008571
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008572 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8573 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008574
Marcel Holtmann901801b2013-10-06 23:55:51 -07008575 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008576}
Johan Hedberga88a9652011-03-30 13:18:12 +03008577
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008578void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8579 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008580{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008581 struct mgmt_ev_device_found *ev;
8582 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8583 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008584
Johan Hedbergb644ba32012-01-17 21:48:47 +02008585 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008586
Johan Hedbergb644ba32012-01-17 21:48:47 +02008587 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008588
Johan Hedbergb644ba32012-01-17 21:48:47 +02008589 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008590 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008591 ev->rssi = rssi;
8592
8593 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008594 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008595
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008596 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008597
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008598 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008599}
Johan Hedberg314b2382011-04-27 10:29:57 -04008600
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008601void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008602{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008603 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008604
Marcel Holtmann181d6952020-05-06 09:57:47 +02008605 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008606
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008607 memset(&ev, 0, sizeof(ev));
8608 ev.type = hdev->discovery.type;
8609 ev.discovering = discovering;
8610
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008611 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008612}
Antti Julku5e762442011-08-25 16:48:02 +03008613
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008614static struct hci_mgmt_chan chan = {
8615 .channel = HCI_CHANNEL_CONTROL,
8616 .handler_count = ARRAY_SIZE(mgmt_handlers),
8617 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008618 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008619};
8620
8621int mgmt_init(void)
8622{
8623 return hci_mgmt_chan_register(&chan);
8624}
8625
8626void mgmt_exit(void)
8627{
8628 hci_mgmt_chan_unregister(&chan);
8629}