blob: 0b711ad80f6bd15400869ddca860a3f58d440818 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Alain Michaud17896402020-06-11 02:01:57 +000039#include "mgmt_config.h"
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +020040#include "msft.h"
Johan Hedberg03811012010-12-08 00:21:06 +020041
Johan Hedberg2da9c552012-02-17 14:39:28 +020042#define MGMT_VERSION 1
Marcel Holtmann79bf1182020-07-30 19:40:11 +020043#define MGMT_REVISION 18
Johan Hedberg02d98122010-12-13 21:07:04 +020044
Johan Hedberge70bb2e2012-02-13 16:59:33 +020045static const u16 mgmt_commands[] = {
46 MGMT_OP_READ_INDEX_LIST,
47 MGMT_OP_READ_INFO,
48 MGMT_OP_SET_POWERED,
49 MGMT_OP_SET_DISCOVERABLE,
50 MGMT_OP_SET_CONNECTABLE,
51 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030052 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020053 MGMT_OP_SET_LINK_SECURITY,
54 MGMT_OP_SET_SSP,
55 MGMT_OP_SET_HS,
56 MGMT_OP_SET_LE,
57 MGMT_OP_SET_DEV_CLASS,
58 MGMT_OP_SET_LOCAL_NAME,
59 MGMT_OP_ADD_UUID,
60 MGMT_OP_REMOVE_UUID,
61 MGMT_OP_LOAD_LINK_KEYS,
62 MGMT_OP_LOAD_LONG_TERM_KEYS,
63 MGMT_OP_DISCONNECT,
64 MGMT_OP_GET_CONNECTIONS,
65 MGMT_OP_PIN_CODE_REPLY,
66 MGMT_OP_PIN_CODE_NEG_REPLY,
67 MGMT_OP_SET_IO_CAPABILITY,
68 MGMT_OP_PAIR_DEVICE,
69 MGMT_OP_CANCEL_PAIR_DEVICE,
70 MGMT_OP_UNPAIR_DEVICE,
71 MGMT_OP_USER_CONFIRM_REPLY,
72 MGMT_OP_USER_CONFIRM_NEG_REPLY,
73 MGMT_OP_USER_PASSKEY_REPLY,
74 MGMT_OP_USER_PASSKEY_NEG_REPLY,
75 MGMT_OP_READ_LOCAL_OOB_DATA,
76 MGMT_OP_ADD_REMOTE_OOB_DATA,
77 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
78 MGMT_OP_START_DISCOVERY,
79 MGMT_OP_STOP_DISCOVERY,
80 MGMT_OP_CONFIRM_NAME,
81 MGMT_OP_BLOCK_DEVICE,
82 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070083 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030084 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030085 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070086 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070087 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080088 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080089 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020090 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020091 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020092 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030093 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020094 MGMT_OP_ADD_DEVICE,
95 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030096 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020097 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020098 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020099 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200100 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100101 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700102 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700103 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700104 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700105 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700106 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100107 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200108 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200109 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200110 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000111 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000112 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200113 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200114 MGMT_OP_READ_EXP_FEATURES_INFO,
115 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000116 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
117 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200118 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
119 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200120 MGMT_OP_GET_DEVICE_FLAGS,
121 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200122 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200123 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200124 MGMT_OP_REMOVE_ADV_MONITOR,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200125};
126
127static const u16 mgmt_events[] = {
128 MGMT_EV_CONTROLLER_ERROR,
129 MGMT_EV_INDEX_ADDED,
130 MGMT_EV_INDEX_REMOVED,
131 MGMT_EV_NEW_SETTINGS,
132 MGMT_EV_CLASS_OF_DEV_CHANGED,
133 MGMT_EV_LOCAL_NAME_CHANGED,
134 MGMT_EV_NEW_LINK_KEY,
135 MGMT_EV_NEW_LONG_TERM_KEY,
136 MGMT_EV_DEVICE_CONNECTED,
137 MGMT_EV_DEVICE_DISCONNECTED,
138 MGMT_EV_CONNECT_FAILED,
139 MGMT_EV_PIN_CODE_REQUEST,
140 MGMT_EV_USER_CONFIRM_REQUEST,
141 MGMT_EV_USER_PASSKEY_REQUEST,
142 MGMT_EV_AUTH_FAILED,
143 MGMT_EV_DEVICE_FOUND,
144 MGMT_EV_DISCOVERING,
145 MGMT_EV_DEVICE_BLOCKED,
146 MGMT_EV_DEVICE_UNBLOCKED,
147 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300148 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800149 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700150 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200151 MGMT_EV_DEVICE_ADDED,
152 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300153 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200154 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200155 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200156 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700157 MGMT_EV_EXT_INDEX_ADDED,
158 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700159 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700160 MGMT_EV_ADVERTISING_ADDED,
161 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200162 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200163 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200164 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200165 MGMT_EV_DEVICE_FLAGS_CHANGED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700166 MGMT_EV_CONTROLLER_SUSPEND,
167 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200168};
169
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700170static const u16 mgmt_untrusted_commands[] = {
171 MGMT_OP_READ_INDEX_LIST,
172 MGMT_OP_READ_INFO,
173 MGMT_OP_READ_UNCONF_INDEX_LIST,
174 MGMT_OP_READ_CONFIG_INFO,
175 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200176 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200177 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200178 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000179 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200180 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700181};
182
183static const u16 mgmt_untrusted_events[] = {
184 MGMT_EV_INDEX_ADDED,
185 MGMT_EV_INDEX_REMOVED,
186 MGMT_EV_NEW_SETTINGS,
187 MGMT_EV_CLASS_OF_DEV_CHANGED,
188 MGMT_EV_LOCAL_NAME_CHANGED,
189 MGMT_EV_UNCONF_INDEX_ADDED,
190 MGMT_EV_UNCONF_INDEX_REMOVED,
191 MGMT_EV_NEW_CONFIG_OPTIONS,
192 MGMT_EV_EXT_INDEX_ADDED,
193 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200194 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200195 MGMT_EV_EXP_FEATURE_CHANGED,
Miao-chen Choub52729f2020-06-17 16:39:16 +0200196 MGMT_EV_ADV_MONITOR_ADDED,
Miao-chen Choucdde92e2020-06-17 16:39:17 +0200197 MGMT_EV_ADV_MONITOR_REMOVED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700198};
199
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800200#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200201
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200202#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
203 "\x00\x00\x00\x00\x00\x00\x00\x00"
204
Johan Hedbergca69b792011-11-11 18:10:00 +0200205/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000206static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200207 MGMT_STATUS_SUCCESS,
208 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
209 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
210 MGMT_STATUS_FAILED, /* Hardware Failure */
211 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
212 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200213 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200214 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
215 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
216 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
217 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
218 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
219 MGMT_STATUS_BUSY, /* Command Disallowed */
220 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
221 MGMT_STATUS_REJECTED, /* Rejected Security */
222 MGMT_STATUS_REJECTED, /* Rejected Personal */
223 MGMT_STATUS_TIMEOUT, /* Host Timeout */
224 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
225 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
226 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
227 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
228 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
229 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
230 MGMT_STATUS_BUSY, /* Repeated Attempts */
231 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
232 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
233 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
234 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
235 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
236 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
237 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
238 MGMT_STATUS_FAILED, /* Unspecified Error */
239 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
240 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
241 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
242 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
243 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
244 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
245 MGMT_STATUS_FAILED, /* Unit Link Key Used */
246 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
247 MGMT_STATUS_TIMEOUT, /* Instant Passed */
248 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
249 MGMT_STATUS_FAILED, /* Transaction Collision */
250 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
251 MGMT_STATUS_REJECTED, /* QoS Rejected */
252 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
253 MGMT_STATUS_REJECTED, /* Insufficient Security */
254 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
255 MGMT_STATUS_BUSY, /* Role Switch Pending */
256 MGMT_STATUS_FAILED, /* Slot Violation */
257 MGMT_STATUS_FAILED, /* Role Switch Failed */
258 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
259 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
260 MGMT_STATUS_BUSY, /* Host Busy Pairing */
261 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
262 MGMT_STATUS_BUSY, /* Controller Busy */
263 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
264 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
265 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
266 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
267 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
268};
269
270static u8 mgmt_status(u8 hci_status)
271{
272 if (hci_status < ARRAY_SIZE(mgmt_status_table))
273 return mgmt_status_table[hci_status];
274
275 return MGMT_STATUS_FAILED;
276}
277
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700278static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
279 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700280{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700281 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
282 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700283}
284
Marcel Holtmann72000df2015-03-16 16:11:21 -0700285static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
286 u16 len, int flag, struct sock *skip_sk)
287{
288 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
289 flag, skip_sk);
290}
291
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200292static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
293 struct sock *skip_sk)
294{
295 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700296 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200297}
298
Johan Hedberg85813a72015-10-21 18:02:59 +0300299static u8 le_addr_type(u8 mgmt_addr_type)
300{
301 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
302 return ADDR_LE_DEV_PUBLIC;
303 else
304 return ADDR_LE_DEV_RANDOM;
305}
306
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200307void mgmt_fill_version_info(void *ver)
308{
309 struct mgmt_rp_read_version *rp = ver;
310
311 rp->version = MGMT_VERSION;
312 rp->revision = cpu_to_le16(MGMT_REVISION);
313}
314
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300315static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
316 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200317{
318 struct mgmt_rp_read_version rp;
319
Marcel Holtmann181d6952020-05-06 09:57:47 +0200320 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200321
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200322 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200323
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200324 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
325 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200326}
327
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300328static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
329 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200330{
331 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700332 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200333 size_t rp_size;
334 int i, err;
335
Marcel Holtmann181d6952020-05-06 09:57:47 +0200336 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200337
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700338 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
339 num_commands = ARRAY_SIZE(mgmt_commands);
340 num_events = ARRAY_SIZE(mgmt_events);
341 } else {
342 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
343 num_events = ARRAY_SIZE(mgmt_untrusted_events);
344 }
345
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
347
348 rp = kmalloc(rp_size, GFP_KERNEL);
349 if (!rp)
350 return -ENOMEM;
351
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700352 rp->num_commands = cpu_to_le16(num_commands);
353 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200354
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700355 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
356 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200357
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700358 for (i = 0; i < num_commands; i++, opcode++)
359 put_unaligned_le16(mgmt_commands[i], opcode);
360
361 for (i = 0; i < num_events; i++, opcode++)
362 put_unaligned_le16(mgmt_events[i], opcode);
363 } else {
364 __le16 *opcode = rp->opcodes;
365
366 for (i = 0; i < num_commands; i++, opcode++)
367 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
368
369 for (i = 0; i < num_events; i++, opcode++)
370 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
371 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200372
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200373 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
374 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200375 kfree(rp);
376
377 return err;
378}
379
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300380static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
381 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200382{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200383 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200384 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200385 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200386 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300387 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200388
Marcel Holtmann181d6952020-05-06 09:57:47 +0200389 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200390
391 read_lock(&hci_dev_list_lock);
392
393 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300394 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200395 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700396 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700397 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200398 }
399
Johan Hedberga38528f2011-01-22 06:46:43 +0200400 rp_len = sizeof(*rp) + (2 * count);
401 rp = kmalloc(rp_len, GFP_ATOMIC);
402 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100403 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100405 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200406
Johan Hedberg476e44c2012-10-19 20:10:46 +0300407 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200408 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700409 if (hci_dev_test_flag(d, HCI_SETUP) ||
410 hci_dev_test_flag(d, HCI_CONFIG) ||
411 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200412 continue;
413
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200414 /* Devices marked as raw-only are neither configured
415 * nor unconfigured controllers.
416 */
417 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700418 continue;
419
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200420 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700421 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700422 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200423 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700424 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200425 }
426
Johan Hedberg476e44c2012-10-19 20:10:46 +0300427 rp->num_controllers = cpu_to_le16(count);
428 rp_len = sizeof(*rp) + (2 * count);
429
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200430 read_unlock(&hci_dev_list_lock);
431
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200432 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
433 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200434
Johan Hedberga38528f2011-01-22 06:46:43 +0200435 kfree(rp);
436
437 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200438}
439
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200440static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
441 void *data, u16 data_len)
442{
443 struct mgmt_rp_read_unconf_index_list *rp;
444 struct hci_dev *d;
445 size_t rp_len;
446 u16 count;
447 int err;
448
Marcel Holtmann181d6952020-05-06 09:57:47 +0200449 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200450
451 read_lock(&hci_dev_list_lock);
452
453 count = 0;
454 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200455 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700456 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200457 count++;
458 }
459
460 rp_len = sizeof(*rp) + (2 * count);
461 rp = kmalloc(rp_len, GFP_ATOMIC);
462 if (!rp) {
463 read_unlock(&hci_dev_list_lock);
464 return -ENOMEM;
465 }
466
467 count = 0;
468 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700469 if (hci_dev_test_flag(d, HCI_SETUP) ||
470 hci_dev_test_flag(d, HCI_CONFIG) ||
471 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200472 continue;
473
474 /* Devices marked as raw-only are neither configured
475 * nor unconfigured controllers.
476 */
477 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
478 continue;
479
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200480 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700481 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200482 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200483 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200484 }
485 }
486
487 rp->num_controllers = cpu_to_le16(count);
488 rp_len = sizeof(*rp) + (2 * count);
489
490 read_unlock(&hci_dev_list_lock);
491
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200492 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
493 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200494
495 kfree(rp);
496
497 return err;
498}
499
Marcel Holtmann96f14742015-03-14 19:27:57 -0700500static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
501 void *data, u16 data_len)
502{
503 struct mgmt_rp_read_ext_index_list *rp;
504 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700505 u16 count;
506 int err;
507
Marcel Holtmann181d6952020-05-06 09:57:47 +0200508 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700509
510 read_lock(&hci_dev_list_lock);
511
512 count = 0;
513 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200514 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700515 count++;
516 }
517
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600518 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700519 if (!rp) {
520 read_unlock(&hci_dev_list_lock);
521 return -ENOMEM;
522 }
523
524 count = 0;
525 list_for_each_entry(d, &hci_dev_list, list) {
526 if (hci_dev_test_flag(d, HCI_SETUP) ||
527 hci_dev_test_flag(d, HCI_CONFIG) ||
528 hci_dev_test_flag(d, HCI_USER_CHANNEL))
529 continue;
530
531 /* Devices marked as raw-only are neither configured
532 * nor unconfigured controllers.
533 */
534 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
535 continue;
536
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200537 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700538 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
539 rp->entry[count].type = 0x01;
540 else
541 rp->entry[count].type = 0x00;
542 } else if (d->dev_type == HCI_AMP) {
543 rp->entry[count].type = 0x02;
544 } else {
545 continue;
546 }
547
548 rp->entry[count].bus = d->bus;
549 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200550 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700551 }
552
553 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700554
555 read_unlock(&hci_dev_list_lock);
556
557 /* If this command is called at least once, then all the
558 * default index and unconfigured index events are disabled
559 * and from now on only extended index events are used.
560 */
561 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
562 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
563 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
564
565 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600566 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
567 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700568
569 kfree(rp);
570
571 return err;
572}
573
Marcel Holtmanndbece372014-07-04 18:11:55 +0200574static bool is_configured(struct hci_dev *hdev)
575{
576 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700577 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578 return false;
579
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800580 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
581 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200582 !bacmp(&hdev->public_addr, BDADDR_ANY))
583 return false;
584
585 return true;
586}
587
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200588static __le32 get_missing_options(struct hci_dev *hdev)
589{
590 u32 options = 0;
591
Marcel Holtmanndbece372014-07-04 18:11:55 +0200592 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700593 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200594 options |= MGMT_OPTION_EXTERNAL_CONFIG;
595
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800596 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
597 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598 !bacmp(&hdev->public_addr, BDADDR_ANY))
599 options |= MGMT_OPTION_PUBLIC_ADDRESS;
600
601 return cpu_to_le32(options);
602}
603
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200604static int new_options(struct hci_dev *hdev, struct sock *skip)
605{
606 __le32 options = get_missing_options(hdev);
607
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200608 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
609 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200610}
611
Marcel Holtmanndbece372014-07-04 18:11:55 +0200612static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
613{
614 __le32 options = get_missing_options(hdev);
615
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200616 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
617 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200618}
619
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200620static int read_config_info(struct sock *sk, struct hci_dev *hdev,
621 void *data, u16 data_len)
622{
623 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200624 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200625
Marcel Holtmann181d6952020-05-06 09:57:47 +0200626 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200627
628 hci_dev_lock(hdev);
629
630 memset(&rp, 0, sizeof(rp));
631 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200632
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200633 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
634 options |= MGMT_OPTION_EXTERNAL_CONFIG;
635
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200636 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200637 options |= MGMT_OPTION_PUBLIC_ADDRESS;
638
639 rp.supported_options = cpu_to_le32(options);
640 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200641
642 hci_dev_unlock(hdev);
643
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200644 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
645 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200646}
647
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530648static u32 get_supported_phys(struct hci_dev *hdev)
649{
650 u32 supported_phys = 0;
651
652 if (lmp_bredr_capable(hdev)) {
653 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
654
655 if (hdev->features[0][0] & LMP_3SLOT)
656 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
657
658 if (hdev->features[0][0] & LMP_5SLOT)
659 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
660
661 if (lmp_edr_2m_capable(hdev)) {
662 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
663
664 if (lmp_edr_3slot_capable(hdev))
665 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
666
667 if (lmp_edr_5slot_capable(hdev))
668 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
669
670 if (lmp_edr_3m_capable(hdev)) {
671 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
672
673 if (lmp_edr_3slot_capable(hdev))
674 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
675
676 if (lmp_edr_5slot_capable(hdev))
677 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
678 }
679 }
680 }
681
682 if (lmp_le_capable(hdev)) {
683 supported_phys |= MGMT_PHY_LE_1M_TX;
684 supported_phys |= MGMT_PHY_LE_1M_RX;
685
686 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
687 supported_phys |= MGMT_PHY_LE_2M_TX;
688 supported_phys |= MGMT_PHY_LE_2M_RX;
689 }
690
691 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
692 supported_phys |= MGMT_PHY_LE_CODED_TX;
693 supported_phys |= MGMT_PHY_LE_CODED_RX;
694 }
695 }
696
697 return supported_phys;
698}
699
700static u32 get_selected_phys(struct hci_dev *hdev)
701{
702 u32 selected_phys = 0;
703
704 if (lmp_bredr_capable(hdev)) {
705 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
706
707 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
708 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
709
710 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
711 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
712
713 if (lmp_edr_2m_capable(hdev)) {
714 if (!(hdev->pkt_type & HCI_2DH1))
715 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
716
717 if (lmp_edr_3slot_capable(hdev) &&
718 !(hdev->pkt_type & HCI_2DH3))
719 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
720
721 if (lmp_edr_5slot_capable(hdev) &&
722 !(hdev->pkt_type & HCI_2DH5))
723 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
724
725 if (lmp_edr_3m_capable(hdev)) {
726 if (!(hdev->pkt_type & HCI_3DH1))
727 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
728
729 if (lmp_edr_3slot_capable(hdev) &&
730 !(hdev->pkt_type & HCI_3DH3))
731 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
732
733 if (lmp_edr_5slot_capable(hdev) &&
734 !(hdev->pkt_type & HCI_3DH5))
735 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
736 }
737 }
738 }
739
740 if (lmp_le_capable(hdev)) {
741 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
742 selected_phys |= MGMT_PHY_LE_1M_TX;
743
744 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
745 selected_phys |= MGMT_PHY_LE_1M_RX;
746
747 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
748 selected_phys |= MGMT_PHY_LE_2M_TX;
749
750 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
751 selected_phys |= MGMT_PHY_LE_2M_RX;
752
753 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
754 selected_phys |= MGMT_PHY_LE_CODED_TX;
755
756 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
757 selected_phys |= MGMT_PHY_LE_CODED_RX;
758 }
759
760 return selected_phys;
761}
762
763static u32 get_configurable_phys(struct hci_dev *hdev)
764{
765 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
766 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
767}
768
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200769static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200770{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200772
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200773 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300774 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800775 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300776 settings |= MGMT_SETTING_CONNECTABLE;
777 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200778
Andre Guedesed3fa312012-07-24 15:03:46 -0300779 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500780 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
781 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200782 settings |= MGMT_SETTING_BREDR;
783 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700784
785 if (lmp_ssp_capable(hdev)) {
786 settings |= MGMT_SETTING_SSP;
787 settings |= MGMT_SETTING_HS;
788 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800789
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800790 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800791 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000792
Alain Michaud00bce3f2020-03-05 16:14:59 +0000793 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000794 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000795 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700796 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100797
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300798 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200799 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300800 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200801 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800802 settings |= MGMT_SETTING_STATIC_ADDRESS;
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +0530803
804 /* When the experimental feature for LL Privacy support is
805 * enabled, then advertising is no longer supported.
806 */
807 if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
808 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300809 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200810
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200811 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
812 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200813 settings |= MGMT_SETTING_CONFIGURATION;
814
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530815 settings |= MGMT_SETTING_PHY_CONFIGURATION;
816
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200817 return settings;
818}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200819
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200820static u32 get_current_settings(struct hci_dev *hdev)
821{
822 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200823
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200824 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100825 settings |= MGMT_SETTING_POWERED;
826
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700827 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828 settings |= MGMT_SETTING_CONNECTABLE;
829
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700830 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500831 settings |= MGMT_SETTING_FAST_CONNECTABLE;
832
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700833 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200834 settings |= MGMT_SETTING_DISCOVERABLE;
835
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700836 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300837 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200838
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700839 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200840 settings |= MGMT_SETTING_BREDR;
841
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700842 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200843 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200844
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700845 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200847
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700848 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200849 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200850
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700851 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200852 settings |= MGMT_SETTING_HS;
853
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700854 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300855 settings |= MGMT_SETTING_ADVERTISING;
856
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700857 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800858 settings |= MGMT_SETTING_SECURE_CONN;
859
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700860 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800861 settings |= MGMT_SETTING_DEBUG_KEYS;
862
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700863 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200864 settings |= MGMT_SETTING_PRIVACY;
865
Marcel Holtmann93690c22015-03-06 10:11:21 -0800866 /* The current setting for static address has two purposes. The
867 * first is to indicate if the static address will be used and
868 * the second is to indicate if it is actually set.
869 *
870 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700871 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800872 * address is actually used decides if the flag is set or not.
873 *
874 * For single mode LE only controllers and dual-mode controllers
875 * with BR/EDR disabled, the existence of the static address will
876 * be evaluated.
877 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700878 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700879 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800880 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
881 if (bacmp(&hdev->static_addr, BDADDR_ANY))
882 settings |= MGMT_SETTING_STATIC_ADDRESS;
883 }
884
Alain Michaud00bce3f2020-03-05 16:14:59 +0000885 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
886 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
887
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200888 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200889}
890
Johan Hedberg333ae952015-03-17 13:48:47 +0200891static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
892{
893 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
894}
895
Johan Hedberg333ae952015-03-17 13:48:47 +0200896static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
897 struct hci_dev *hdev,
898 const void *data)
899{
900 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
901}
902
Johan Hedbergf2252572015-11-18 12:49:20 +0200903u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300904{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200905 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300906
907 /* If there's a pending mgmt command the flags will not yet have
908 * their final values, so check for this first.
909 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200910 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300911 if (cmd) {
912 struct mgmt_mode *cp = cmd->param;
913 if (cp->val == 0x01)
914 return LE_AD_GENERAL;
915 else if (cp->val == 0x02)
916 return LE_AD_LIMITED;
917 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700918 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300919 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700920 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300921 return LE_AD_GENERAL;
922 }
923
924 return 0;
925}
926
Johan Hedbergf2252572015-11-18 12:49:20 +0200927bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700928{
929 struct mgmt_pending_cmd *cmd;
930
931 /* If there's a pending mgmt command the flag will not yet have
932 * it's final value, so check for this first.
933 */
934 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
935 if (cmd) {
936 struct mgmt_mode *cp = cmd->param;
937
938 return cp->val;
939 }
940
941 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
942}
943
Johan Hedberg7d785252011-12-15 00:47:39 +0200944static void service_cache_off(struct work_struct *work)
945{
946 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500948 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200949
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700950 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200951 return;
952
Johan Hedberg890ea892013-03-15 17:06:52 -0500953 hci_req_init(&req, hdev);
954
Johan Hedberg7d785252011-12-15 00:47:39 +0200955 hci_dev_lock(hdev);
956
Johan Hedbergb1a89172015-11-25 16:15:42 +0200957 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200958 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200959
960 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500961
962 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200963}
964
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200965static void rpa_expired(struct work_struct *work)
966{
967 struct hci_dev *hdev = container_of(work, struct hci_dev,
968 rpa_expired.work);
969 struct hci_request req;
970
Marcel Holtmann181d6952020-05-06 09:57:47 +0200971 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200972
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700973 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200974
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700975 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200976 return;
977
978 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200979 * controller happens in the hci_req_enable_advertising()
980 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200981 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200982 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530983 if (ext_adv_capable(hdev))
984 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
985 else
986 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200987 hci_req_run(&req, NULL);
988}
989
Johan Hedberg6a919082012-02-28 06:17:26 +0200990static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200991{
Marcel Holtmann238be782015-03-13 02:11:06 -0700992 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200993 return;
994
Johan Hedberg4f87da82012-03-02 19:55:56 +0200995 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200996 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200997
Johan Hedberg4f87da82012-03-02 19:55:56 +0200998 /* Non-mgmt controlled devices get this bit set
999 * implicitly so that pairing works for them, however
1000 * for mgmt we require user-space to explicitly enable
1001 * it
1002 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001003 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001004}
1005
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001006static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001007 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001008{
1009 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001010
Marcel Holtmann181d6952020-05-06 09:57:47 +02001011 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001012
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001013 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001014
Johan Hedberg03811012010-12-08 00:21:06 +02001015 memset(&rp, 0, sizeof(rp));
1016
Johan Hedberg03811012010-12-08 00:21:06 +02001017 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001018
1019 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001020 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001021
1022 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1023 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1024
1025 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001026
1027 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001028 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001031
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001032 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1033 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001034}
1035
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001036static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1037{
1038 u16 eir_len = 0;
1039 size_t name_len;
1040
1041 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1042 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1043 hdev->dev_class, 3);
1044
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001045 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1046 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1047 hdev->appearance);
1048
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001049 name_len = strlen(hdev->dev_name);
1050 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1051 hdev->dev_name, name_len);
1052
1053 name_len = strlen(hdev->short_name);
1054 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1055 hdev->short_name, name_len);
1056
1057 return eir_len;
1058}
1059
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001060static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1061 void *data, u16 data_len)
1062{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001063 char buf[512];
1064 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001065 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001066
Marcel Holtmann181d6952020-05-06 09:57:47 +02001067 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001068
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001069 memset(&buf, 0, sizeof(buf));
1070
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001071 hci_dev_lock(hdev);
1072
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001073 bacpy(&rp->bdaddr, &hdev->bdaddr);
1074
1075 rp->version = hdev->hci_ver;
1076 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1077
1078 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1079 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001080
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001081
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001082 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001083 rp->eir_len = cpu_to_le16(eir_len);
1084
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001085 hci_dev_unlock(hdev);
1086
1087 /* If this command is called at least once, then the events
1088 * for class of device and local name changes are disabled
1089 * and only the new extended controller information event
1090 * is used.
1091 */
1092 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1093 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1094 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1095
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001096 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1097 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001098}
1099
1100static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1101{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001102 char buf[512];
1103 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1104 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001105
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001106 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001107
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001108 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1109 ev->eir_len = cpu_to_le16(eir_len);
1110
1111 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1112 sizeof(*ev) + eir_len,
1113 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001114}
1115
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001116static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001117{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001118 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001119
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001120 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1121 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001122}
1123
Marcel Holtmann1904a852015-01-11 13:50:44 -08001124static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001125{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001126 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001127
Johan Hedberga3172b72014-02-28 09:33:44 +02001128 if (hci_conn_count(hdev) == 0) {
1129 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001130 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001131 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001132}
1133
Johan Hedbergf2252572015-11-18 12:49:20 +02001134void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001135{
1136 struct mgmt_ev_advertising_added ev;
1137
1138 ev.instance = instance;
1139
1140 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1141}
1142
Johan Hedbergf2252572015-11-18 12:49:20 +02001143void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1144 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001145{
1146 struct mgmt_ev_advertising_removed ev;
1147
1148 ev.instance = instance;
1149
1150 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1151}
1152
Florian Grandel7816b822015-06-18 03:16:45 +02001153static void cancel_adv_timeout(struct hci_dev *hdev)
1154{
1155 if (hdev->adv_instance_timeout) {
1156 hdev->adv_instance_timeout = 0;
1157 cancel_delayed_work(&hdev->adv_instance_expire);
1158 }
1159}
1160
Johan Hedberg8b064a32014-02-24 14:52:22 +02001161static int clean_up_hci_state(struct hci_dev *hdev)
1162{
1163 struct hci_request req;
1164 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001165 bool discov_stopped;
1166 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001167
1168 hci_req_init(&req, hdev);
1169
1170 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1171 test_bit(HCI_PSCAN, &hdev->flags)) {
1172 u8 scan = 0x00;
1173 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1174 }
1175
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001176 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001177
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001178 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001179 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001180
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001181 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001182
1183 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001184 /* 0x15 == Terminated due to Power Off */
1185 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186 }
1187
Johan Hedberg23a48092014-07-08 16:05:06 +03001188 err = hci_req_run(&req, clean_up_hci_complete);
1189 if (!err && discov_stopped)
1190 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1191
1192 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001193}
1194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001197{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001198 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001199 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001200 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201
Marcel Holtmann181d6952020-05-06 09:57:47 +02001202 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001203
Johan Hedberga7e80f22013-01-09 16:05:19 +02001204 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001205 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1206 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001207
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001208 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209
Johan Hedberg333ae952015-03-17 13:48:47 +02001210 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001211 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1212 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001213 goto failed;
1214 }
1215
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001216 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001217 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001218 goto failed;
1219 }
1220
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001221 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1222 if (!cmd) {
1223 err = -ENOMEM;
1224 goto failed;
1225 }
1226
Johan Hedberg8b064a32014-02-24 14:52:22 +02001227 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001228 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001229 err = 0;
1230 } else {
1231 /* Disconnect connections, stop scans, etc */
1232 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001233 if (!err)
1234 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1235 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001236
Johan Hedberg8b064a32014-02-24 14:52:22 +02001237 /* ENODATA means there were no HCI commands queued */
1238 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001239 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001240 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1241 err = 0;
1242 }
1243 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001244
1245failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001246 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001247 return err;
1248}
1249
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001250static int new_settings(struct hci_dev *hdev, struct sock *skip)
1251{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001252 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001253
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001254 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1255 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001256}
1257
Johan Hedberg91a668b2014-07-09 13:28:26 +03001258int mgmt_new_settings(struct hci_dev *hdev)
1259{
1260 return new_settings(hdev, NULL);
1261}
1262
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001263struct cmd_lookup {
1264 struct sock *sk;
1265 struct hci_dev *hdev;
1266 u8 mgmt_status;
1267};
1268
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001269static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001270{
1271 struct cmd_lookup *match = data;
1272
1273 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1274
1275 list_del(&cmd->list);
1276
1277 if (match->sk == NULL) {
1278 match->sk = cmd->sk;
1279 sock_hold(match->sk);
1280 }
1281
1282 mgmt_pending_free(cmd);
1283}
1284
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001285static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001286{
1287 u8 *status = data;
1288
Johan Hedberga69e8372015-03-06 21:08:53 +02001289 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001290 mgmt_pending_remove(cmd);
1291}
1292
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001293static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001294{
1295 if (cmd->cmd_complete) {
1296 u8 *status = data;
1297
1298 cmd->cmd_complete(cmd, *status);
1299 mgmt_pending_remove(cmd);
1300
1301 return;
1302 }
1303
1304 cmd_status_rsp(cmd, data);
1305}
1306
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001307static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001308{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001309 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1310 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001311}
1312
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001313static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001314{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001315 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1316 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001317}
1318
Johan Hedberge6fe7982013-10-02 15:45:22 +03001319static u8 mgmt_bredr_support(struct hci_dev *hdev)
1320{
1321 if (!lmp_bredr_capable(hdev))
1322 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001323 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001324 return MGMT_STATUS_REJECTED;
1325 else
1326 return MGMT_STATUS_SUCCESS;
1327}
1328
1329static u8 mgmt_le_support(struct hci_dev *hdev)
1330{
1331 if (!lmp_le_capable(hdev))
1332 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001333 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001334 return MGMT_STATUS_REJECTED;
1335 else
1336 return MGMT_STATUS_SUCCESS;
1337}
1338
Johan Hedbergaed1a882015-11-22 17:24:44 +03001339void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001340{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001341 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001342
Marcel Holtmann181d6952020-05-06 09:57:47 +02001343 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001344
1345 hci_dev_lock(hdev);
1346
Johan Hedberg333ae952015-03-17 13:48:47 +02001347 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348 if (!cmd)
1349 goto unlock;
1350
1351 if (status) {
1352 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001353 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001354 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001355 goto remove_cmd;
1356 }
1357
Johan Hedbergaed1a882015-11-22 17:24:44 +03001358 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1359 hdev->discov_timeout > 0) {
1360 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1361 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001362 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001363
1364 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001365 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001366
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001367remove_cmd:
1368 mgmt_pending_remove(cmd);
1369
1370unlock:
1371 hci_dev_unlock(hdev);
1372}
1373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001375 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001376{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001377 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001378 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001379 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001380 int err;
1381
Marcel Holtmann181d6952020-05-06 09:57:47 +02001382 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001383
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001384 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1385 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001386 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1387 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001388
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001389 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
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 Hedberga7e80f22013-01-09 16:05:19 +02001392
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001393 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001394
1395 /* Disabling discoverable requires that no timeout is set,
1396 * and enabling limited discoverable requires a timeout.
1397 */
1398 if ((cp->val == 0x00 && timeout > 0) ||
1399 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001400 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001402
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001403 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001404
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001405 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001406 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1407 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408 goto failed;
1409 }
1410
Johan Hedberg333ae952015-03-17 13:48:47 +02001411 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1412 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001413 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1414 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001415 goto failed;
1416 }
1417
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001418 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001419 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1420 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001421 goto failed;
1422 }
1423
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001424 if (hdev->advertising_paused) {
1425 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1426 MGMT_STATUS_BUSY);
1427 goto failed;
1428 }
1429
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001430 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001431 bool changed = false;
1432
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001433 /* Setting limited discoverable when powered off is
1434 * not a valid operation since it requires a timeout
1435 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1436 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001437 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001438 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001439 changed = true;
1440 }
1441
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001442 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001443 if (err < 0)
1444 goto failed;
1445
1446 if (changed)
1447 err = new_settings(hdev, sk);
1448
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001449 goto failed;
1450 }
1451
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001452 /* If the current mode is the same, then just update the timeout
1453 * value with the new value. And if only the timeout gets updated,
1454 * then no need for any HCI transactions.
1455 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001456 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1457 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1458 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001459 cancel_delayed_work(&hdev->discov_off);
1460 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001461
Marcel Holtmann36261542013-10-15 08:28:51 -07001462 if (cp->val && hdev->discov_timeout > 0) {
1463 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001464 queue_delayed_work(hdev->req_workqueue,
1465 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001466 }
1467
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001468 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001469 goto failed;
1470 }
1471
1472 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1473 if (!cmd) {
1474 err = -ENOMEM;
1475 goto failed;
1476 }
1477
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001478 /* Cancel any potential discoverable timeout that might be
1479 * still active and store new timeout value. The arming of
1480 * the timeout happens in the complete handler.
1481 */
1482 cancel_delayed_work(&hdev->discov_off);
1483 hdev->discov_timeout = timeout;
1484
Johan Hedbergaed1a882015-11-22 17:24:44 +03001485 if (cp->val)
1486 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1487 else
1488 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1489
Johan Hedbergb456f872013-10-19 23:38:22 +03001490 /* Limited discoverable mode */
1491 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001492 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001493 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001494 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001495
Johan Hedbergaed1a882015-11-22 17:24:44 +03001496 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1497 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001498
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001499failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001500 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001501 return err;
1502}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001503
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001504void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001505{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001506 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001507
Marcel Holtmann181d6952020-05-06 09:57:47 +02001508 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001509
1510 hci_dev_lock(hdev);
1511
Johan Hedberg333ae952015-03-17 13:48:47 +02001512 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001513 if (!cmd)
1514 goto unlock;
1515
Johan Hedberg37438c12013-10-14 16:20:05 +03001516 if (status) {
1517 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001518 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001519 goto remove_cmd;
1520 }
1521
Johan Hedberg2b76f452013-03-15 17:07:04 -05001522 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001523 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001524
Johan Hedberg37438c12013-10-14 16:20:05 +03001525remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001526 mgmt_pending_remove(cmd);
1527
1528unlock:
1529 hci_dev_unlock(hdev);
1530}
1531
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001532static int set_connectable_update_settings(struct hci_dev *hdev,
1533 struct sock *sk, u8 val)
1534{
1535 bool changed = false;
1536 int err;
1537
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001538 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001539 changed = true;
1540
1541 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001542 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001543 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001544 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1545 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001546 }
1547
1548 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1549 if (err < 0)
1550 return err;
1551
Johan Hedberg562064e2014-07-08 16:35:34 +03001552 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001553 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001554 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001555 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001556 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001557
1558 return 0;
1559}
1560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001562 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001563{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001564 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001565 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001566 int err;
1567
Marcel Holtmann181d6952020-05-06 09:57:47 +02001568 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001569
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001570 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1571 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1573 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001574
Johan Hedberga7e80f22013-01-09 16:05:19 +02001575 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001576 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1577 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001579 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001580
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001581 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001582 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001583 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001584 }
1585
Johan Hedberg333ae952015-03-17 13:48:47 +02001586 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1587 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001588 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1589 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001590 goto failed;
1591 }
1592
Johan Hedberg73f22f62010-12-29 16:00:25 +02001593 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1594 if (!cmd) {
1595 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001596 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001597 }
1598
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001599 if (cp->val) {
1600 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1601 } else {
1602 if (hdev->discov_timeout > 0)
1603 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001604
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001605 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1606 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1607 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001608 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001609
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001610 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1611 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001612
1613failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001614 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001615 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001616}
1617
Johan Hedbergb2939472014-07-30 09:22:23 +03001618static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001619 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001621 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001622 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001623 int err;
1624
Marcel Holtmann181d6952020-05-06 09:57:47 +02001625 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001626
Johan Hedberga7e80f22013-01-09 16:05:19 +02001627 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001628 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1629 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001630
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001631 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001632
1633 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001634 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001635 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001636 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001637
Johan Hedbergb2939472014-07-30 09:22:23 +03001638 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001639 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001640 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001641
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001642 if (changed) {
1643 /* In limited privacy mode the change of bondable mode
1644 * may affect the local advertising address.
1645 */
1646 if (hdev_is_powered(hdev) &&
1647 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1648 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1649 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1650 queue_work(hdev->req_workqueue,
1651 &hdev->discoverable_update);
1652
Marcel Holtmann55594352013-10-06 16:11:57 -07001653 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001654 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001655
Marcel Holtmann55594352013-10-06 16:11:57 -07001656unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001657 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001658 return err;
1659}
1660
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001661static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1662 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001663{
1664 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001665 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001666 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001667 int err;
1668
Marcel Holtmann181d6952020-05-06 09:57:47 +02001669 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001670
Johan Hedberge6fe7982013-10-02 15:45:22 +03001671 status = mgmt_bredr_support(hdev);
1672 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001673 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1674 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001675
Johan Hedberga7e80f22013-01-09 16:05:19 +02001676 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1678 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001679
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001680 hci_dev_lock(hdev);
1681
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001682 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001683 bool changed = false;
1684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001685 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001686 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001687 changed = true;
1688 }
1689
1690 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1691 if (err < 0)
1692 goto failed;
1693
1694 if (changed)
1695 err = new_settings(hdev, sk);
1696
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001697 goto failed;
1698 }
1699
Johan Hedberg333ae952015-03-17 13:48:47 +02001700 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001701 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1702 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001703 goto failed;
1704 }
1705
1706 val = !!cp->val;
1707
1708 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1709 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1710 goto failed;
1711 }
1712
1713 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1714 if (!cmd) {
1715 err = -ENOMEM;
1716 goto failed;
1717 }
1718
1719 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1720 if (err < 0) {
1721 mgmt_pending_remove(cmd);
1722 goto failed;
1723 }
1724
1725failed:
1726 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001727 return err;
1728}
1729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001731{
1732 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001733 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001734 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001735 int err;
1736
Marcel Holtmann181d6952020-05-06 09:57:47 +02001737 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001738
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001739 status = mgmt_bredr_support(hdev);
1740 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001741 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001742
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001743 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001744 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1745 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001746
Johan Hedberga7e80f22013-01-09 16:05:19 +02001747 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001750
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001751 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001752
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001753 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001754 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001755
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001756 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001757 changed = !hci_dev_test_and_set_flag(hdev,
1758 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001759 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001760 changed = hci_dev_test_and_clear_flag(hdev,
1761 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001762 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001763 changed = hci_dev_test_and_clear_flag(hdev,
1764 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001765 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001766 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001767 }
1768
1769 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1770 if (err < 0)
1771 goto failed;
1772
1773 if (changed)
1774 err = new_settings(hdev, sk);
1775
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001776 goto failed;
1777 }
1778
Johan Hedberg333ae952015-03-17 13:48:47 +02001779 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001780 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1781 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001782 goto failed;
1783 }
1784
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001785 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001786 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1787 goto failed;
1788 }
1789
1790 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1791 if (!cmd) {
1792 err = -ENOMEM;
1793 goto failed;
1794 }
1795
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001796 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001797 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1798 sizeof(cp->val), &cp->val);
1799
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001800 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001801 if (err < 0) {
1802 mgmt_pending_remove(cmd);
1803 goto failed;
1804 }
1805
1806failed:
1807 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001808 return err;
1809}
1810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001812{
1813 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001814 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001815 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001816 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001817
Marcel Holtmann181d6952020-05-06 09:57:47 +02001818 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001819
Johan Hedberge6fe7982013-10-02 15:45:22 +03001820 status = mgmt_bredr_support(hdev);
1821 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001823
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001824 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001825 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1826 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001827
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001828 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001829 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1830 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001831
Johan Hedberga7e80f22013-01-09 16:05:19 +02001832 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001833 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1834 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001835
Marcel Holtmannee392692013-10-01 22:59:23 -07001836 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001837
Johan Hedberg333ae952015-03-17 13:48:47 +02001838 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001839 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1840 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001841 goto unlock;
1842 }
1843
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001844 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001845 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001846 } else {
1847 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001848 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1849 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001850 goto unlock;
1851 }
1852
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001853 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001854 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001855
1856 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1857 if (err < 0)
1858 goto unlock;
1859
1860 if (changed)
1861 err = new_settings(hdev, sk);
1862
1863unlock:
1864 hci_dev_unlock(hdev);
1865 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001866}
1867
Marcel Holtmann1904a852015-01-11 13:50:44 -08001868static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001869{
1870 struct cmd_lookup match = { NULL, hdev };
1871
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301872 hci_dev_lock(hdev);
1873
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001874 if (status) {
1875 u8 mgmt_err = mgmt_status(status);
1876
1877 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1878 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301879 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001880 }
1881
1882 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1883
1884 new_settings(hdev, match.sk);
1885
1886 if (match.sk)
1887 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001888
1889 /* Make sure the controller has a good default for
1890 * advertising data. Restrict the update to when LE
1891 * has actually been enabled. During power on, the
1892 * update in powered_update_hci will take care of it.
1893 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001894 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001895 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001896 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301897 if (ext_adv_capable(hdev)) {
1898 int err;
1899
1900 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1901 if (!err)
1902 __hci_req_update_scan_rsp_data(&req, 0x00);
1903 } else {
1904 __hci_req_update_adv_data(&req, 0x00);
1905 __hci_req_update_scan_rsp_data(&req, 0x00);
1906 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001907 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001908 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001909 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301910
1911unlock:
1912 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001913}
1914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001916{
1917 struct mgmt_mode *cp = data;
1918 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001919 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001920 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001921 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001922 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001923
Marcel Holtmann181d6952020-05-06 09:57:47 +02001924 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001925
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001926 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001927 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1928 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001929
Johan Hedberga7e80f22013-01-09 16:05:19 +02001930 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001931 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1932 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001933
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001934 /* Bluetooth single mode LE only controllers or dual-mode
1935 * controllers configured as LE only devices, do not allow
1936 * switching LE off. These have either LE enabled explicitly
1937 * or BR/EDR has been previously switched off.
1938 *
1939 * When trying to enable an already enabled LE, then gracefully
1940 * send a positive response. Trying to disable it however will
1941 * result into rejection.
1942 */
1943 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1944 if (cp->val == 0x01)
1945 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1946
Johan Hedberga69e8372015-03-06 21:08:53 +02001947 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1948 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001949 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001950
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001951 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001952
1953 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001954 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001955
Florian Grandel847818d2015-06-18 03:16:46 +02001956 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001957 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001958
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001959 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001960 bool changed = false;
1961
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001962 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001963 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001964 changed = true;
1965 }
1966
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001967 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001968 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001969 changed = true;
1970 }
1971
Johan Hedberg06199cf2012-02-22 16:37:11 +02001972 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1973 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001974 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001975
1976 if (changed)
1977 err = new_settings(hdev, sk);
1978
Johan Hedberg1de028c2012-02-29 19:55:35 -08001979 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001980 }
1981
Johan Hedberg333ae952015-03-17 13:48:47 +02001982 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1983 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001984 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1985 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001986 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001987 }
1988
1989 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1990 if (!cmd) {
1991 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001992 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001993 }
1994
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001995 hci_req_init(&req, hdev);
1996
Johan Hedberg06199cf2012-02-22 16:37:11 +02001997 memset(&hci_cp, 0, sizeof(hci_cp));
1998
1999 if (val) {
2000 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002001 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002002 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002003 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002004 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05302005
2006 if (ext_adv_capable(hdev))
2007 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002008 }
2009
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002010 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2011 &hci_cp);
2012
2013 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302014 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002015 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002016
Johan Hedberg1de028c2012-02-29 19:55:35 -08002017unlock:
2018 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002019 return err;
2020}
2021
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002022/* This is a helper function to test for pending mgmt commands that can
2023 * cause CoD or EIR HCI commands. We can only allow one such pending
2024 * mgmt command at a time since otherwise we cannot easily track what
2025 * the current values are, will be, and based on that calculate if a new
2026 * HCI command needs to be sent and if yes with what value.
2027 */
2028static bool pending_eir_or_class(struct hci_dev *hdev)
2029{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002030 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002031
2032 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2033 switch (cmd->opcode) {
2034 case MGMT_OP_ADD_UUID:
2035 case MGMT_OP_REMOVE_UUID:
2036 case MGMT_OP_SET_DEV_CLASS:
2037 case MGMT_OP_SET_POWERED:
2038 return true;
2039 }
2040 }
2041
2042 return false;
2043}
2044
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002045static const u8 bluetooth_base_uuid[] = {
2046 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2047 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2048};
2049
2050static u8 get_uuid_size(const u8 *uuid)
2051{
2052 u32 val;
2053
2054 if (memcmp(uuid, bluetooth_base_uuid, 12))
2055 return 128;
2056
2057 val = get_unaligned_le32(&uuid[12]);
2058 if (val > 0xffff)
2059 return 32;
2060
2061 return 16;
2062}
2063
Johan Hedberg92da6092013-03-15 17:06:55 -05002064static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2065{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002066 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002067
2068 hci_dev_lock(hdev);
2069
Johan Hedberg333ae952015-03-17 13:48:47 +02002070 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002071 if (!cmd)
2072 goto unlock;
2073
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002074 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2075 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002076
2077 mgmt_pending_remove(cmd);
2078
2079unlock:
2080 hci_dev_unlock(hdev);
2081}
2082
Marcel Holtmann1904a852015-01-11 13:50:44 -08002083static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002084{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002085 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002086
2087 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2088}
2089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002091{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002092 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002093 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002094 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002095 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096 int err;
2097
Marcel Holtmann181d6952020-05-06 09:57:47 +02002098 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002100 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002101
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002102 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002103 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2104 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002105 goto failed;
2106 }
2107
Andre Guedes92c4c202012-06-07 19:05:44 -03002108 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002109 if (!uuid) {
2110 err = -ENOMEM;
2111 goto failed;
2112 }
2113
2114 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002115 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002116 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117
Johan Hedbergde66aa62013-01-27 00:31:27 +02002118 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119
Johan Hedberg890ea892013-03-15 17:06:52 -05002120 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002121
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002122 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002123 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002124
Johan Hedberg92da6092013-03-15 17:06:55 -05002125 err = hci_req_run(&req, add_uuid_complete);
2126 if (err < 0) {
2127 if (err != -ENODATA)
2128 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002129
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002130 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2131 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002132 goto failed;
2133 }
2134
2135 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002136 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002137 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002138 goto failed;
2139 }
2140
2141 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002142
2143failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002145 return err;
2146}
2147
Johan Hedberg24b78d02012-02-23 23:24:30 +02002148static bool enable_service_cache(struct hci_dev *hdev)
2149{
2150 if (!hdev_is_powered(hdev))
2151 return false;
2152
Marcel Holtmann238be782015-03-13 02:11:06 -07002153 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002154 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2155 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002156 return true;
2157 }
2158
2159 return false;
2160}
2161
Marcel Holtmann1904a852015-01-11 13:50:44 -08002162static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002163{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002164 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002165
2166 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2167}
2168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002170 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002172 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002173 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002174 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002175 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 -05002176 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002177 int err, found;
2178
Marcel Holtmann181d6952020-05-06 09:57:47 +02002179 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002181 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002182
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002183 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002184 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2185 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002186 goto unlock;
2187 }
2188
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002190 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002191
Johan Hedberg24b78d02012-02-23 23:24:30 +02002192 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002193 err = mgmt_cmd_complete(sk, hdev->id,
2194 MGMT_OP_REMOVE_UUID,
2195 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002196 goto unlock;
2197 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002198
Johan Hedberg9246a862012-02-23 21:33:16 +02002199 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002200 }
2201
2202 found = 0;
2203
Johan Hedberg056341c2013-01-27 00:31:30 +02002204 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002205 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2206 continue;
2207
2208 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002209 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002210 found++;
2211 }
2212
2213 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002214 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2215 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002216 goto unlock;
2217 }
2218
Johan Hedberg9246a862012-02-23 21:33:16 +02002219update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002220 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002221
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002222 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002223 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002224
Johan Hedberg92da6092013-03-15 17:06:55 -05002225 err = hci_req_run(&req, remove_uuid_complete);
2226 if (err < 0) {
2227 if (err != -ENODATA)
2228 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002229
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002230 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2231 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002232 goto unlock;
2233 }
2234
2235 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002236 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002237 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002238 goto unlock;
2239 }
2240
2241 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002242
2243unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002244 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002245 return err;
2246}
2247
Marcel Holtmann1904a852015-01-11 13:50:44 -08002248static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002249{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002250 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002251
2252 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2253}
2254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002255static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002256 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002257{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002258 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002259 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002260 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261 int err;
2262
Marcel Holtmann181d6952020-05-06 09:57:47 +02002263 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002264
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002265 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002266 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2267 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002270
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002271 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002272 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2273 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002274 goto unlock;
2275 }
2276
2277 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002278 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2279 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002280 goto unlock;
2281 }
2282
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002283 hdev->major_class = cp->major;
2284 hdev->minor_class = cp->minor;
2285
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002286 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002287 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2288 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002289 goto unlock;
2290 }
2291
Johan Hedberg890ea892013-03-15 17:06:52 -05002292 hci_req_init(&req, hdev);
2293
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002294 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002295 hci_dev_unlock(hdev);
2296 cancel_delayed_work_sync(&hdev->service_cache);
2297 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002298 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002299 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002300
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002301 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002302
Johan Hedberg92da6092013-03-15 17:06:55 -05002303 err = hci_req_run(&req, set_class_complete);
2304 if (err < 0) {
2305 if (err != -ENODATA)
2306 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002307
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002308 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2309 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002310 goto unlock;
2311 }
2312
2313 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002314 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002315 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002316 goto unlock;
2317 }
2318
2319 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002320
Johan Hedbergb5235a62012-02-21 14:32:24 +02002321unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002322 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002323 return err;
2324}
2325
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002326static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002327 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002330 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2331 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002332 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002333 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002334 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002335
Marcel Holtmann181d6952020-05-06 09:57:47 +02002336 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002337
2338 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002339 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2340 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002341
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002342 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002343 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002344 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2345 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002348 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002349
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002350 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002351 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002352 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2353 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002354 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2355 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002356 }
2357
Johan Hedberg4ae143012013-01-20 14:27:13 +02002358 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002359 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002361
Marcel Holtmann181d6952020-05-06 09:57:47 +02002362 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2363 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002365 for (i = 0; i < key_count; i++) {
2366 struct mgmt_link_key_info *key = &cp->keys[i];
2367
Marcel Holtmann8e991132014-01-10 02:07:25 -08002368 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002369 return mgmt_cmd_status(sk, hdev->id,
2370 MGMT_OP_LOAD_LINK_KEYS,
2371 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002372 }
2373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375
2376 hci_link_keys_clear(hdev);
2377
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002379 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002381 changed = hci_dev_test_and_clear_flag(hdev,
2382 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002383
2384 if (changed)
2385 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002386
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002387 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002388 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002389
Alain Michaud600a8742020-01-07 00:43:17 +00002390 if (hci_is_blocked_key(hdev,
2391 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2392 key->val)) {
2393 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2394 &key->addr.bdaddr);
2395 continue;
2396 }
2397
Johan Hedberg58e92932014-06-24 14:00:26 +03002398 /* Always ignore debug keys and require a new pairing if
2399 * the user wants to use them.
2400 */
2401 if (key->type == HCI_LK_DEBUG_COMBINATION)
2402 continue;
2403
Johan Hedberg7652ff62014-06-24 13:15:49 +03002404 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2405 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002406 }
2407
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002408 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002411
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002412 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002413}
2414
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002415static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002417{
2418 struct mgmt_ev_device_unpaired ev;
2419
2420 bacpy(&ev.addr.bdaddr, bdaddr);
2421 ev.addr.type = addr_type;
2422
2423 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002425}
2426
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002427static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002428 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002429{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002430 struct mgmt_cp_unpair_device *cp = data;
2431 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002432 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002433 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002434 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002435 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002436 int err;
2437
Johan Hedberga8a1d192011-11-10 15:54:38 +02002438 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002439 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2440 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002441
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002442 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002443 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2444 MGMT_STATUS_INVALID_PARAMS,
2445 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002446
Johan Hedberg118da702013-01-20 14:27:20 +02002447 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002448 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2449 MGMT_STATUS_INVALID_PARAMS,
2450 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002451
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002452 hci_dev_lock(hdev);
2453
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002454 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002455 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2456 MGMT_STATUS_NOT_POWERED, &rp,
2457 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002458 goto unlock;
2459 }
2460
Johan Hedberge0b2b272014-02-18 17:14:31 +02002461 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002462 /* If disconnection is requested, then look up the
2463 * connection. If the remote device is connected, it
2464 * will be later used to terminate the link.
2465 *
2466 * Setting it to NULL explicitly will cause no
2467 * termination of the link.
2468 */
2469 if (cp->disconnect)
2470 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2471 &cp->addr.bdaddr);
2472 else
2473 conn = NULL;
2474
Johan Hedberg124f6e32012-02-09 13:50:12 +02002475 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002476 if (err < 0) {
2477 err = mgmt_cmd_complete(sk, hdev->id,
2478 MGMT_OP_UNPAIR_DEVICE,
2479 MGMT_STATUS_NOT_PAIRED, &rp,
2480 sizeof(rp));
2481 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002482 }
2483
Johan Hedbergec182f02015-10-21 18:03:03 +03002484 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002485 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002486
Johan Hedbergec182f02015-10-21 18:03:03 +03002487 /* LE address type */
2488 addr_type = le_addr_type(cp->addr.type);
2489
Matias Karhumaacb28c302018-09-26 09:13:46 +03002490 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2491 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002492 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002493 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2494 MGMT_STATUS_NOT_PAIRED, &rp,
2495 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002496 goto unlock;
2497 }
2498
Johan Hedbergec182f02015-10-21 18:03:03 +03002499 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2500 if (!conn) {
2501 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2502 goto done;
2503 }
2504
Johan Hedbergc81d5552015-10-22 09:38:35 +03002505
Johan Hedbergec182f02015-10-21 18:03:03 +03002506 /* Defer clearing up the connection parameters until closing to
2507 * give a chance of keeping them if a repairing happens.
2508 */
2509 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2510
Johan Hedbergfc643612015-10-22 09:38:31 +03002511 /* Disable auto-connection parameters if present */
2512 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2513 if (params) {
2514 if (params->explicit_connect)
2515 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2516 else
2517 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2518 }
2519
Johan Hedbergec182f02015-10-21 18:03:03 +03002520 /* If disconnection is not requested, then clear the connection
2521 * variable so that the link is not terminated.
2522 */
2523 if (!cp->disconnect)
2524 conn = NULL;
2525
2526done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002527 /* If the connection variable is set, then termination of the
2528 * link is requested.
2529 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002530 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002531 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2532 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002533 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002534 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002535 }
2536
Johan Hedberg124f6e32012-02-09 13:50:12 +02002537 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002539 if (!cmd) {
2540 err = -ENOMEM;
2541 goto unlock;
2542 }
2543
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002544 cmd->cmd_complete = addr_cmd_complete;
2545
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002546 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002547 if (err < 0)
2548 mgmt_pending_remove(cmd);
2549
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002550unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002551 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002552 return err;
2553}
2554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002555static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002558 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002559 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002560 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002561 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002562 int err;
2563
Marcel Holtmann181d6952020-05-06 09:57:47 +02002564 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565
Johan Hedberg06a63b12013-01-20 14:27:21 +02002566 memset(&rp, 0, sizeof(rp));
2567 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2568 rp.addr.type = cp->addr.type;
2569
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002570 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002571 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2572 MGMT_STATUS_INVALID_PARAMS,
2573 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002574
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002575 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576
2577 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002578 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2579 MGMT_STATUS_NOT_POWERED, &rp,
2580 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002581 goto failed;
2582 }
2583
Johan Hedberg333ae952015-03-17 13:48:47 +02002584 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002585 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2586 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002587 goto failed;
2588 }
2589
Andre Guedes591f47f2012-04-24 21:02:49 -03002590 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002591 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2592 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002593 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002594 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2595 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002596
Vishal Agarwalf9607272012-06-13 05:32:43 +05302597 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002598 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2599 MGMT_STATUS_NOT_CONNECTED, &rp,
2600 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002601 goto failed;
2602 }
2603
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002604 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002605 if (!cmd) {
2606 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002607 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002608 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002609
Johan Hedbergf5818c22014-12-05 13:36:02 +02002610 cmd->cmd_complete = generic_cmd_complete;
2611
Johan Hedberge3f2f922014-08-18 20:33:33 +03002612 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002613 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002614 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002615
2616failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002617 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002618 return err;
2619}
2620
Andre Guedes57c14772012-04-24 21:02:50 -03002621static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002622{
2623 switch (link_type) {
2624 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002625 switch (addr_type) {
2626 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002627 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002628
Johan Hedberg48264f02011-11-09 13:58:58 +02002629 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002630 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002631 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002632 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002633
Johan Hedberg4c659c32011-11-07 23:13:39 +02002634 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002635 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002636 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002637 }
2638}
2639
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002640static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2641 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002642{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002643 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002644 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002645 int err;
2646 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002647
Marcel Holtmann181d6952020-05-06 09:57:47 +02002648 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002649
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002650 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002651
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002652 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002653 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2654 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002655 goto unlock;
2656 }
2657
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002658 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002659 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2660 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002661 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002662 }
2663
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002664 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002665 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002666 err = -ENOMEM;
2667 goto unlock;
2668 }
2669
Johan Hedberg2784eb42011-01-21 13:56:35 +02002670 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002671 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002672 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2673 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002674 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002675 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002676 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002677 continue;
2678 i++;
2679 }
2680
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002681 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002682
Johan Hedberg4c659c32011-11-07 23:13:39 +02002683 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002684 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002685 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002686
Johan Hedberga38528f2011-01-22 06:46:43 +02002687 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002688
2689unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002690 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002691 return err;
2692}
2693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002694static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002696{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002697 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002698 int err;
2699
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002700 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002701 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002702 if (!cmd)
2703 return -ENOMEM;
2704
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002705 cmd->cmd_complete = addr_cmd_complete;
2706
Johan Hedbergd8457692012-02-17 14:24:57 +02002707 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002708 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002709 if (err < 0)
2710 mgmt_pending_remove(cmd);
2711
2712 return err;
2713}
2714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002715static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002718 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002719 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002721 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722 int err;
2723
Marcel Holtmann181d6952020-05-06 09:57:47 +02002724 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002726 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002727
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002728 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002729 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2730 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002731 goto failed;
2732 }
2733
Johan Hedbergd8457692012-02-17 14:24:57 +02002734 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002735 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002736 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2737 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002738 goto failed;
2739 }
2740
2741 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002742 struct mgmt_cp_pin_code_neg_reply ncp;
2743
2744 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002745
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002746 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002749 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002750 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2751 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002752
2753 goto failed;
2754 }
2755
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002756 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002757 if (!cmd) {
2758 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002759 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002760 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002761
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002762 cmd->cmd_complete = addr_cmd_complete;
2763
Johan Hedbergd8457692012-02-17 14:24:57 +02002764 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002765 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002766 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002767
2768 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2769 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002770 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002771
2772failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002773 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002774 return err;
2775}
2776
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002777static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2778 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002779{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002781
Marcel Holtmann181d6952020-05-06 09:57:47 +02002782 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002783
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002784 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002785 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002787
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002788 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002789
2790 hdev->io_capability = cp->io_capability;
2791
Marcel Holtmann181d6952020-05-06 09:57:47 +02002792 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002794 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002795
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002796 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2797 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002798}
2799
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002800static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002801{
2802 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002803 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002804
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002805 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002806 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2807 continue;
2808
Johan Hedberge9a416b2011-02-19 12:05:56 -03002809 if (cmd->user_data != conn)
2810 continue;
2811
2812 return cmd;
2813 }
2814
2815 return NULL;
2816}
2817
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002818static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819{
2820 struct mgmt_rp_pair_device rp;
2821 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002822 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002823
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002824 bacpy(&rp.addr.bdaddr, &conn->dst);
2825 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002826
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002827 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2828 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002829
2830 /* So we don't get further callbacks for this connection */
2831 conn->connect_cfm_cb = NULL;
2832 conn->security_cfm_cb = NULL;
2833 conn->disconn_cfm_cb = NULL;
2834
David Herrmann76a68ba2013-04-06 20:28:37 +02002835 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002836
2837 /* The device is paired so there is no need to remove
2838 * its connection parameters anymore.
2839 */
2840 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002841
2842 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002843
2844 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002845}
2846
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002847void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2848{
2849 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002850 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002851
2852 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002853 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002854 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002855 mgmt_pending_remove(cmd);
2856 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002857}
2858
Johan Hedberge9a416b2011-02-19 12:05:56 -03002859static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2860{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002861 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002862
2863 BT_DBG("status %u", status);
2864
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002865 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002866 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002867 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002868 return;
2869 }
2870
2871 cmd->cmd_complete(cmd, mgmt_status(status));
2872 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002873}
2874
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002875static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302876{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002877 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302878
2879 BT_DBG("status %u", status);
2880
2881 if (!status)
2882 return;
2883
2884 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002885 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302886 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002887 return;
2888 }
2889
2890 cmd->cmd_complete(cmd, mgmt_status(status));
2891 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302892}
2893
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002894static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002896{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002897 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002898 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002899 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002900 u8 sec_level, auth_type;
2901 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002902 int err;
2903
Marcel Holtmann181d6952020-05-06 09:57:47 +02002904 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002905
Szymon Jancf950a30e2013-01-18 12:48:07 +01002906 memset(&rp, 0, sizeof(rp));
2907 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2908 rp.addr.type = cp->addr.type;
2909
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002910 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002911 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2912 MGMT_STATUS_INVALID_PARAMS,
2913 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002914
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002915 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002916 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2917 MGMT_STATUS_INVALID_PARAMS,
2918 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002919
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002920 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002921
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002922 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002923 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2924 MGMT_STATUS_NOT_POWERED, &rp,
2925 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002926 goto unlock;
2927 }
2928
Johan Hedberg55e76b32015-03-10 22:34:40 +02002929 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2931 MGMT_STATUS_ALREADY_PAIRED, &rp,
2932 sizeof(rp));
2933 goto unlock;
2934 }
2935
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002936 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002937 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002938
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002939 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002940 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002941 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002942 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002943 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002944 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002945
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002946 /* When pairing a new device, it is expected to remember
2947 * this device for future connections. Adding the connection
2948 * parameter information ahead of time allows tracking
2949 * of the slave preferred values and will speed up any
2950 * further connection establishment.
2951 *
2952 * If connection parameters already exist, then they
2953 * will be kept and this function does nothing.
2954 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002955 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2956
2957 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2958 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002959
Manish Mandlik76b13992020-06-17 16:39:19 +02002960 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2961 sec_level, HCI_LE_CONN_TIMEOUT,
2962 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002963 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002964
Ville Tervo30e76272011-02-22 16:10:53 -03002965 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002966 int status;
2967
2968 if (PTR_ERR(conn) == -EBUSY)
2969 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002970 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2971 status = MGMT_STATUS_NOT_SUPPORTED;
2972 else if (PTR_ERR(conn) == -ECONNREFUSED)
2973 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002974 else
2975 status = MGMT_STATUS_CONNECT_FAILED;
2976
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002977 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2978 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002979 goto unlock;
2980 }
2981
2982 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002983 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002984 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2985 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002986 goto unlock;
2987 }
2988
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002989 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002990 if (!cmd) {
2991 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002992 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002993 goto unlock;
2994 }
2995
Johan Hedberg04ab2742014-12-05 13:36:04 +02002996 cmd->cmd_complete = pairing_complete;
2997
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002998 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002999 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003000 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003001 conn->security_cfm_cb = pairing_complete_cb;
3002 conn->disconn_cfm_cb = pairing_complete_cb;
3003 } else {
3004 conn->connect_cfm_cb = le_pairing_complete_cb;
3005 conn->security_cfm_cb = le_pairing_complete_cb;
3006 conn->disconn_cfm_cb = le_pairing_complete_cb;
3007 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003008
Johan Hedberge9a416b2011-02-19 12:05:56 -03003009 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003010 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003011
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003012 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003013 hci_conn_security(conn, sec_level, auth_type, true)) {
3014 cmd->cmd_complete(cmd, 0);
3015 mgmt_pending_remove(cmd);
3016 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003017
3018 err = 0;
3019
3020unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003021 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003022 return err;
3023}
3024
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3026 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003027{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003028 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003029 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003030 struct hci_conn *conn;
3031 int err;
3032
Marcel Holtmann181d6952020-05-06 09:57:47 +02003033 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003034
Johan Hedberg28424702012-02-02 04:02:29 +02003035 hci_dev_lock(hdev);
3036
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003037 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003038 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3039 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003040 goto unlock;
3041 }
3042
Johan Hedberg333ae952015-03-17 13:48:47 +02003043 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003044 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003045 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003047 goto unlock;
3048 }
3049
3050 conn = cmd->user_data;
3051
3052 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003053 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3054 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003055 goto unlock;
3056 }
3057
Johan Hedberga511b352014-12-11 21:45:45 +02003058 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3059 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003060
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003061 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3062 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003063
3064 /* Since user doesn't want to proceed with the connection, abort any
3065 * ongoing pairing and then terminate the link if it was created
3066 * because of the pair device action.
3067 */
3068 if (addr->type == BDADDR_BREDR)
3069 hci_remove_link_key(hdev, &addr->bdaddr);
3070 else
3071 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3072 le_addr_type(addr->type));
3073
3074 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3075 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3076
Johan Hedberg28424702012-02-02 04:02:29 +02003077unlock:
3078 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003079 return err;
3080}
3081
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003082static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003083 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003085{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003086 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003087 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003088 int err;
3089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003090 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003091
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003092 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003093 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3094 MGMT_STATUS_NOT_POWERED, addr,
3095 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003096 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003097 }
3098
Johan Hedberg1707c602013-03-15 17:07:15 -05003099 if (addr->type == BDADDR_BREDR)
3100 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003101 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003102 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3103 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003104
Johan Hedberg272d90d2012-02-09 15:26:12 +02003105 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003106 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3107 MGMT_STATUS_NOT_CONNECTED, addr,
3108 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003109 goto done;
3110 }
3111
Johan Hedberg1707c602013-03-15 17:07:15 -05003112 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003113 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003114 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003115 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3116 MGMT_STATUS_SUCCESS, addr,
3117 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003118 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003119 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3120 MGMT_STATUS_FAILED, addr,
3121 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003122
Brian Gix47c15e22011-11-16 13:53:14 -08003123 goto done;
3124 }
3125
Johan Hedberg1707c602013-03-15 17:07:15 -05003126 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003127 if (!cmd) {
3128 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003129 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003130 }
3131
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003132 cmd->cmd_complete = addr_cmd_complete;
3133
Brian Gix0df4c182011-11-16 13:53:13 -08003134 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003135 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3136 struct hci_cp_user_passkey_reply cp;
3137
Johan Hedberg1707c602013-03-15 17:07:15 -05003138 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003139 cp.passkey = passkey;
3140 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3141 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003142 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3143 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003144
Johan Hedberga664b5b2011-02-19 12:06:02 -03003145 if (err < 0)
3146 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003147
Brian Gix0df4c182011-11-16 13:53:13 -08003148done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003149 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003150 return err;
3151}
3152
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303153static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3154 void *data, u16 len)
3155{
3156 struct mgmt_cp_pin_code_neg_reply *cp = data;
3157
Marcel Holtmann181d6952020-05-06 09:57:47 +02003158 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303159
Johan Hedberg1707c602013-03-15 17:07:15 -05003160 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303161 MGMT_OP_PIN_CODE_NEG_REPLY,
3162 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3163}
3164
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3166 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003167{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003168 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003169
Marcel Holtmann181d6952020-05-06 09:57:47 +02003170 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003171
3172 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3174 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -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_CONFIRM_REPLY,
3178 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003179}
3180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003182 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003183{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003184 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003185
Marcel Holtmann181d6952020-05-06 09:57:47 +02003186 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -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_CONFIRM_NEG_REPLY,
3190 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003191}
3192
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003193static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3194 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003195{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003196 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003197
Marcel Holtmann181d6952020-05-06 09:57:47 +02003198 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003199
Johan Hedberg1707c602013-03-15 17:07:15 -05003200 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 MGMT_OP_USER_PASSKEY_REPLY,
3202 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003203}
3204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003205static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003208 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003209
Marcel Holtmann181d6952020-05-06 09:57:47 +02003210 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003211
Johan Hedberg1707c602013-03-15 17:07:15 -05003212 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003213 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3214 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003215}
3216
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003217static void adv_expire(struct hci_dev *hdev, u32 flags)
3218{
3219 struct adv_info *adv_instance;
3220 struct hci_request req;
3221 int err;
3222
3223 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3224 if (!adv_instance)
3225 return;
3226
3227 /* stop if current instance doesn't need to be changed */
3228 if (!(adv_instance->flags & flags))
3229 return;
3230
3231 cancel_adv_timeout(hdev);
3232
3233 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3234 if (!adv_instance)
3235 return;
3236
3237 hci_req_init(&req, hdev);
3238 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3239 true);
3240 if (err)
3241 return;
3242
3243 hci_req_run(&req, NULL);
3244}
3245
Marcel Holtmann1904a852015-01-11 13:50:44 -08003246static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003247{
3248 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003249 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003250
Marcel Holtmann181d6952020-05-06 09:57:47 +02003251 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003252
3253 hci_dev_lock(hdev);
3254
Johan Hedberg333ae952015-03-17 13:48:47 +02003255 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003256 if (!cmd)
3257 goto unlock;
3258
3259 cp = cmd->param;
3260
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003261 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003262 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3263 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003264 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003265 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3266 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003267
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003268 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3269 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3270 }
3271
Johan Hedberg13928972013-03-15 17:07:00 -05003272 mgmt_pending_remove(cmd);
3273
3274unlock:
3275 hci_dev_unlock(hdev);
3276}
3277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003278static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003279 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003280{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003281 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003282 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003283 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003284 int err;
3285
Marcel Holtmann181d6952020-05-06 09:57:47 +02003286 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003287
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003288 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003289
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003290 /* If the old values are the same as the new ones just return a
3291 * direct command complete event.
3292 */
3293 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3294 !memcmp(hdev->short_name, cp->short_name,
3295 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003296 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3297 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003298 goto failed;
3299 }
3300
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003301 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003302
Johan Hedbergb5235a62012-02-21 14:32:24 +02003303 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003304 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003305
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003306 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3307 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003308 if (err < 0)
3309 goto failed;
3310
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003311 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3312 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003313 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003314
Johan Hedbergb5235a62012-02-21 14:32:24 +02003315 goto failed;
3316 }
3317
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003318 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003319 if (!cmd) {
3320 err = -ENOMEM;
3321 goto failed;
3322 }
3323
Johan Hedberg13928972013-03-15 17:07:00 -05003324 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3325
Johan Hedberg890ea892013-03-15 17:06:52 -05003326 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003327
3328 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003329 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003330 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003331 }
3332
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003333 /* The name is stored in the scan response data and so
3334 * no need to udpate the advertising data here.
3335 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003336 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003337 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003338
Johan Hedberg13928972013-03-15 17:07:00 -05003339 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003340 if (err < 0)
3341 mgmt_pending_remove(cmd);
3342
3343failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003344 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003345 return err;
3346}
3347
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003348static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3349 u16 len)
3350{
3351 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003352 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003353 int err;
3354
Marcel Holtmann181d6952020-05-06 09:57:47 +02003355 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003356
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003357 if (!lmp_le_capable(hdev))
3358 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3359 MGMT_STATUS_NOT_SUPPORTED);
3360
Alain Michaud6613bab2020-01-22 19:47:44 +00003361 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003362
3363 hci_dev_lock(hdev);
3364
Alain Michaud6613bab2020-01-22 19:47:44 +00003365 if (hdev->appearance != appearance) {
3366 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003367
3368 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3369 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003370
3371 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003372 }
3373
3374 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3375 0);
3376
3377 hci_dev_unlock(hdev);
3378
3379 return err;
3380}
3381
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303382static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3383 void *data, u16 len)
3384{
3385 struct mgmt_rp_get_phy_confguration rp;
3386
Marcel Holtmann181d6952020-05-06 09:57:47 +02003387 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303388
3389 hci_dev_lock(hdev);
3390
3391 memset(&rp, 0, sizeof(rp));
3392
3393 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3394 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3395 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3396
3397 hci_dev_unlock(hdev);
3398
3399 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3400 &rp, sizeof(rp));
3401}
3402
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303403int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3404{
3405 struct mgmt_ev_phy_configuration_changed ev;
3406
3407 memset(&ev, 0, sizeof(ev));
3408
3409 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3410
3411 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3412 sizeof(ev), skip);
3413}
3414
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303415static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3416 u16 opcode, struct sk_buff *skb)
3417{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303418 struct mgmt_pending_cmd *cmd;
3419
Marcel Holtmann181d6952020-05-06 09:57:47 +02003420 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303421
3422 hci_dev_lock(hdev);
3423
3424 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3425 if (!cmd)
3426 goto unlock;
3427
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303428 if (status) {
3429 mgmt_cmd_status(cmd->sk, hdev->id,
3430 MGMT_OP_SET_PHY_CONFIGURATION,
3431 mgmt_status(status));
3432 } else {
3433 mgmt_cmd_complete(cmd->sk, hdev->id,
3434 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3435 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303436
3437 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303438 }
3439
3440 mgmt_pending_remove(cmd);
3441
3442unlock:
3443 hci_dev_unlock(hdev);
3444}
3445
3446static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3447 void *data, u16 len)
3448{
3449 struct mgmt_cp_set_phy_confguration *cp = data;
3450 struct hci_cp_le_set_default_phy cp_phy;
3451 struct mgmt_pending_cmd *cmd;
3452 struct hci_request req;
3453 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3454 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303455 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303456 int err;
3457
Marcel Holtmann181d6952020-05-06 09:57:47 +02003458 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303459
3460 configurable_phys = get_configurable_phys(hdev);
3461 supported_phys = get_supported_phys(hdev);
3462 selected_phys = __le32_to_cpu(cp->selected_phys);
3463
3464 if (selected_phys & ~supported_phys)
3465 return mgmt_cmd_status(sk, hdev->id,
3466 MGMT_OP_SET_PHY_CONFIGURATION,
3467 MGMT_STATUS_INVALID_PARAMS);
3468
3469 unconfigure_phys = supported_phys & ~configurable_phys;
3470
3471 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3472 return mgmt_cmd_status(sk, hdev->id,
3473 MGMT_OP_SET_PHY_CONFIGURATION,
3474 MGMT_STATUS_INVALID_PARAMS);
3475
3476 if (selected_phys == get_selected_phys(hdev))
3477 return mgmt_cmd_complete(sk, hdev->id,
3478 MGMT_OP_SET_PHY_CONFIGURATION,
3479 0, NULL, 0);
3480
3481 hci_dev_lock(hdev);
3482
3483 if (!hdev_is_powered(hdev)) {
3484 err = mgmt_cmd_status(sk, hdev->id,
3485 MGMT_OP_SET_PHY_CONFIGURATION,
3486 MGMT_STATUS_REJECTED);
3487 goto unlock;
3488 }
3489
3490 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3491 err = mgmt_cmd_status(sk, hdev->id,
3492 MGMT_OP_SET_PHY_CONFIGURATION,
3493 MGMT_STATUS_BUSY);
3494 goto unlock;
3495 }
3496
3497 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3498 pkt_type |= (HCI_DH3 | HCI_DM3);
3499 else
3500 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3501
3502 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3503 pkt_type |= (HCI_DH5 | HCI_DM5);
3504 else
3505 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3506
3507 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3508 pkt_type &= ~HCI_2DH1;
3509 else
3510 pkt_type |= HCI_2DH1;
3511
3512 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3513 pkt_type &= ~HCI_2DH3;
3514 else
3515 pkt_type |= HCI_2DH3;
3516
3517 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3518 pkt_type &= ~HCI_2DH5;
3519 else
3520 pkt_type |= HCI_2DH5;
3521
3522 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3523 pkt_type &= ~HCI_3DH1;
3524 else
3525 pkt_type |= HCI_3DH1;
3526
3527 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3528 pkt_type &= ~HCI_3DH3;
3529 else
3530 pkt_type |= HCI_3DH3;
3531
3532 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3533 pkt_type &= ~HCI_3DH5;
3534 else
3535 pkt_type |= HCI_3DH5;
3536
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303537 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303538 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303539 changed = true;
3540 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303541
3542 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3543 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303544 if (changed)
3545 mgmt_phy_configuration_changed(hdev, sk);
3546
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303547 err = mgmt_cmd_complete(sk, hdev->id,
3548 MGMT_OP_SET_PHY_CONFIGURATION,
3549 0, NULL, 0);
3550
3551 goto unlock;
3552 }
3553
3554 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3555 len);
3556 if (!cmd) {
3557 err = -ENOMEM;
3558 goto unlock;
3559 }
3560
3561 hci_req_init(&req, hdev);
3562
3563 memset(&cp_phy, 0, sizeof(cp_phy));
3564
3565 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3566 cp_phy.all_phys |= 0x01;
3567
3568 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3569 cp_phy.all_phys |= 0x02;
3570
3571 if (selected_phys & MGMT_PHY_LE_1M_TX)
3572 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3573
3574 if (selected_phys & MGMT_PHY_LE_2M_TX)
3575 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3576
3577 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3578 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3579
3580 if (selected_phys & MGMT_PHY_LE_1M_RX)
3581 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3582
3583 if (selected_phys & MGMT_PHY_LE_2M_RX)
3584 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3585
3586 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3587 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3588
3589 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3590
3591 err = hci_req_run_skb(&req, set_default_phy_complete);
3592 if (err < 0)
3593 mgmt_pending_remove(cmd);
3594
3595unlock:
3596 hci_dev_unlock(hdev);
3597
3598 return err;
3599}
3600
Alain Michaud600a8742020-01-07 00:43:17 +00003601static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3602 u16 len)
3603{
3604 int err = MGMT_STATUS_SUCCESS;
3605 struct mgmt_cp_set_blocked_keys *keys = data;
3606 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3607 sizeof(struct mgmt_blocked_key_info));
3608 u16 key_count, expected_len;
3609 int i;
3610
Marcel Holtmann181d6952020-05-06 09:57:47 +02003611 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003612
3613 key_count = __le16_to_cpu(keys->key_count);
3614 if (key_count > max_key_count) {
3615 bt_dev_err(hdev, "too big key_count value %u", key_count);
3616 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3617 MGMT_STATUS_INVALID_PARAMS);
3618 }
3619
3620 expected_len = struct_size(keys, keys, key_count);
3621 if (expected_len != len) {
3622 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3623 expected_len, len);
3624 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3625 MGMT_STATUS_INVALID_PARAMS);
3626 }
3627
3628 hci_dev_lock(hdev);
3629
3630 hci_blocked_keys_clear(hdev);
3631
3632 for (i = 0; i < keys->key_count; ++i) {
3633 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3634
3635 if (!b) {
3636 err = MGMT_STATUS_NO_RESOURCES;
3637 break;
3638 }
3639
3640 b->type = keys->keys[i].type;
3641 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3642 list_add_rcu(&b->list, &hdev->blocked_keys);
3643 }
3644 hci_dev_unlock(hdev);
3645
3646 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3647 err, NULL, 0);
3648}
3649
Alain Michaud00bce3f2020-03-05 16:14:59 +00003650static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3651 void *data, u16 len)
3652{
3653 struct mgmt_mode *cp = data;
3654 int err;
3655 bool changed = false;
3656
Marcel Holtmann181d6952020-05-06 09:57:47 +02003657 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003658
3659 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3660 return mgmt_cmd_status(sk, hdev->id,
3661 MGMT_OP_SET_WIDEBAND_SPEECH,
3662 MGMT_STATUS_NOT_SUPPORTED);
3663
3664 if (cp->val != 0x00 && cp->val != 0x01)
3665 return mgmt_cmd_status(sk, hdev->id,
3666 MGMT_OP_SET_WIDEBAND_SPEECH,
3667 MGMT_STATUS_INVALID_PARAMS);
3668
3669 hci_dev_lock(hdev);
3670
3671 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3672 err = mgmt_cmd_status(sk, hdev->id,
3673 MGMT_OP_SET_WIDEBAND_SPEECH,
3674 MGMT_STATUS_BUSY);
3675 goto unlock;
3676 }
3677
3678 if (hdev_is_powered(hdev) &&
3679 !!cp->val != hci_dev_test_flag(hdev,
3680 HCI_WIDEBAND_SPEECH_ENABLED)) {
3681 err = mgmt_cmd_status(sk, hdev->id,
3682 MGMT_OP_SET_WIDEBAND_SPEECH,
3683 MGMT_STATUS_REJECTED);
3684 goto unlock;
3685 }
3686
3687 if (cp->val)
3688 changed = !hci_dev_test_and_set_flag(hdev,
3689 HCI_WIDEBAND_SPEECH_ENABLED);
3690 else
3691 changed = hci_dev_test_and_clear_flag(hdev,
3692 HCI_WIDEBAND_SPEECH_ENABLED);
3693
3694 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3695 if (err < 0)
3696 goto unlock;
3697
3698 if (changed)
3699 err = new_settings(hdev, sk);
3700
3701unlock:
3702 hci_dev_unlock(hdev);
3703 return err;
3704}
3705
Marcel Holtmannbc292252020-04-03 21:44:05 +02003706static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3707 void *data, u16 data_len)
3708{
3709 char buf[16];
3710 struct mgmt_rp_read_security_info *rp = (void *)buf;
3711 u16 sec_len = 0;
3712 u8 flags = 0;
3713
3714 bt_dev_dbg(hdev, "sock %p", sk);
3715
3716 memset(&buf, 0, sizeof(buf));
3717
3718 hci_dev_lock(hdev);
3719
3720 /* When the Read Simple Pairing Options command is supported, then
3721 * the remote public key validation is supported.
3722 */
3723 if (hdev->commands[41] & 0x08)
3724 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3725
3726 flags |= 0x02; /* Remote public key validation (LE) */
3727
3728 /* When the Read Encryption Key Size command is supported, then the
3729 * encryption key size is enforced.
3730 */
3731 if (hdev->commands[20] & 0x10)
3732 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3733
3734 flags |= 0x08; /* Encryption key size enforcement (LE) */
3735
3736 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3737
3738 /* When the Read Simple Pairing Options command is supported, then
3739 * also max encryption key size information is provided.
3740 */
3741 if (hdev->commands[41] & 0x08)
3742 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3743 hdev->max_enc_key_size);
3744
3745 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3746
3747 rp->sec_len = cpu_to_le16(sec_len);
3748
3749 hci_dev_unlock(hdev);
3750
3751 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3752 rp, sizeof(*rp) + sec_len);
3753}
3754
Marcel Holtmanne625e502020-05-06 09:57:52 +02003755#ifdef CONFIG_BT_FEATURE_DEBUG
3756/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3757static const u8 debug_uuid[16] = {
3758 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3759 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3760};
3761#endif
3762
Alain Michaud15d8ce02020-07-07 17:46:06 +02003763/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3764static const u8 simult_central_periph_uuid[16] = {
3765 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3766 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3767};
3768
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303769/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3770static const u8 rpa_resolution_uuid[16] = {
3771 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3772 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3773};
3774
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003775static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3776 void *data, u16 data_len)
3777{
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303778 char buf[62]; /* Enough space for 3 features */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003779 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3780 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003781 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003782
3783 bt_dev_dbg(hdev, "sock %p", sk);
3784
3785 memset(&buf, 0, sizeof(buf));
3786
Marcel Holtmanne625e502020-05-06 09:57:52 +02003787#ifdef CONFIG_BT_FEATURE_DEBUG
3788 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003789 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003790
3791 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3792 rp->features[idx].flags = cpu_to_le32(flags);
3793 idx++;
3794 }
3795#endif
3796
Alain Michaud15d8ce02020-07-07 17:46:06 +02003797 if (hdev) {
3798 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3799 (hdev->le_states[4] & 0x08) && /* Central */
3800 (hdev->le_states[4] & 0x40) && /* Peripheral */
3801 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3802 flags = BIT(0);
3803 else
3804 flags = 0;
3805
3806 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3807 rp->features[idx].flags = cpu_to_le32(flags);
3808 idx++;
3809 }
3810
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303811 if (hdev && use_ll_privacy(hdev)) {
3812 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3813 flags = BIT(0) | BIT(1);
3814 else
3815 flags = BIT(1);
3816
3817 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3818 rp->features[idx].flags = cpu_to_le32(flags);
3819 idx++;
3820 }
3821
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003822 rp->feature_count = cpu_to_le16(idx);
3823
3824 /* After reading the experimental features information, enable
3825 * the events to update client on any future change.
3826 */
3827 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3828
3829 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3830 MGMT_OP_READ_EXP_FEATURES_INFO,
3831 0, rp, sizeof(*rp) + (20 * idx));
3832}
3833
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303834static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3835 struct sock *skip)
3836{
3837 struct mgmt_ev_exp_feature_changed ev;
3838
3839 memset(&ev, 0, sizeof(ev));
3840 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3841 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3842
3843 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3844 &ev, sizeof(ev),
3845 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3846
3847}
3848
Marcel Holtmanne625e502020-05-06 09:57:52 +02003849#ifdef CONFIG_BT_FEATURE_DEBUG
3850static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3851{
3852 struct mgmt_ev_exp_feature_changed ev;
3853
3854 memset(&ev, 0, sizeof(ev));
3855 memcpy(ev.uuid, debug_uuid, 16);
3856 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3857
3858 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3859 &ev, sizeof(ev),
3860 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3861}
3862#endif
3863
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003864static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3865 void *data, u16 data_len)
3866{
3867 struct mgmt_cp_set_exp_feature *cp = data;
3868 struct mgmt_rp_set_exp_feature rp;
3869
3870 bt_dev_dbg(hdev, "sock %p", sk);
3871
3872 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3873 memset(rp.uuid, 0, 16);
3874 rp.flags = cpu_to_le32(0);
3875
Marcel Holtmanne625e502020-05-06 09:57:52 +02003876#ifdef CONFIG_BT_FEATURE_DEBUG
3877 if (!hdev) {
3878 bool changed = bt_dbg_get();
3879
3880 bt_dbg_set(false);
3881
3882 if (changed)
3883 exp_debug_feature_changed(false, sk);
3884 }
3885#endif
3886
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303887 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3888 bool changed = hci_dev_test_flag(hdev,
3889 HCI_ENABLE_LL_PRIVACY);
3890
3891 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3892
3893 if (changed)
3894 exp_ll_privacy_feature_changed(false, hdev, sk);
3895 }
3896
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003897 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3898
3899 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3900 MGMT_OP_SET_EXP_FEATURE, 0,
3901 &rp, sizeof(rp));
3902 }
3903
Marcel Holtmanne625e502020-05-06 09:57:52 +02003904#ifdef CONFIG_BT_FEATURE_DEBUG
3905 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3906 bool val, changed;
3907 int err;
3908
3909 /* Command requires to use the non-controller index */
3910 if (hdev)
3911 return mgmt_cmd_status(sk, hdev->id,
3912 MGMT_OP_SET_EXP_FEATURE,
3913 MGMT_STATUS_INVALID_INDEX);
3914
3915 /* Parameters are limited to a single octet */
3916 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3917 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3918 MGMT_OP_SET_EXP_FEATURE,
3919 MGMT_STATUS_INVALID_PARAMS);
3920
3921 /* Only boolean on/off is supported */
3922 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3923 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3924 MGMT_OP_SET_EXP_FEATURE,
3925 MGMT_STATUS_INVALID_PARAMS);
3926
3927 val = !!cp->param[0];
3928 changed = val ? !bt_dbg_get() : bt_dbg_get();
3929 bt_dbg_set(val);
3930
3931 memcpy(rp.uuid, debug_uuid, 16);
3932 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3933
3934 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3935
3936 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3937 MGMT_OP_SET_EXP_FEATURE, 0,
3938 &rp, sizeof(rp));
3939
3940 if (changed)
3941 exp_debug_feature_changed(val, sk);
3942
3943 return err;
3944 }
3945#endif
3946
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303947 if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
3948 bool val, changed;
3949 int err;
3950 u32 flags;
3951
3952 /* Command requires to use the controller index */
3953 if (!hdev)
3954 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3955 MGMT_OP_SET_EXP_FEATURE,
3956 MGMT_STATUS_INVALID_INDEX);
3957
3958 /* Changes can only be made when controller is powered down */
3959 if (hdev_is_powered(hdev))
3960 return mgmt_cmd_status(sk, hdev->id,
3961 MGMT_OP_SET_EXP_FEATURE,
3962 MGMT_STATUS_NOT_POWERED);
3963
3964 /* Parameters are limited to a single octet */
3965 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3966 return mgmt_cmd_status(sk, hdev->id,
3967 MGMT_OP_SET_EXP_FEATURE,
3968 MGMT_STATUS_INVALID_PARAMS);
3969
3970 /* Only boolean on/off is supported */
3971 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3972 return mgmt_cmd_status(sk, hdev->id,
3973 MGMT_OP_SET_EXP_FEATURE,
3974 MGMT_STATUS_INVALID_PARAMS);
3975
3976 val = !!cp->param[0];
3977
3978 if (val) {
3979 changed = !hci_dev_test_flag(hdev,
3980 HCI_ENABLE_LL_PRIVACY);
3981 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3982 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
3983
3984 /* Enable LL privacy + supported settings changed */
3985 flags = BIT(0) | BIT(1);
3986 } else {
3987 changed = hci_dev_test_flag(hdev,
3988 HCI_ENABLE_LL_PRIVACY);
3989 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3990
3991 /* Disable LL privacy + supported settings changed */
3992 flags = BIT(1);
3993 }
3994
3995 memcpy(rp.uuid, rpa_resolution_uuid, 16);
3996 rp.flags = cpu_to_le32(flags);
3997
3998 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3999
4000 err = mgmt_cmd_complete(sk, hdev->id,
4001 MGMT_OP_SET_EXP_FEATURE, 0,
4002 &rp, sizeof(rp));
4003
4004 if (changed)
4005 exp_ll_privacy_feature_changed(val, hdev, sk);
4006
4007 return err;
4008 }
4009
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004010 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4011 MGMT_OP_SET_EXP_FEATURE,
4012 MGMT_STATUS_NOT_SUPPORTED);
4013}
4014
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004015#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4016
4017static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4018 u16 data_len)
4019{
4020 struct mgmt_cp_get_device_flags *cp = data;
4021 struct mgmt_rp_get_device_flags rp;
4022 struct bdaddr_list_with_flags *br_params;
4023 struct hci_conn_params *params;
4024 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4025 u32 current_flags = 0;
4026 u8 status = MGMT_STATUS_INVALID_PARAMS;
4027
4028 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4029 &cp->addr.bdaddr, cp->addr.type);
4030
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004031 hci_dev_lock(hdev);
4032
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004033 if (cp->addr.type == BDADDR_BREDR) {
4034 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4035 &cp->addr.bdaddr,
4036 cp->addr.type);
4037 if (!br_params)
4038 goto done;
4039
4040 current_flags = br_params->current_flags;
4041 } else {
4042 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4043 le_addr_type(cp->addr.type));
4044
4045 if (!params)
4046 goto done;
4047
4048 current_flags = params->current_flags;
4049 }
4050
4051 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4052 rp.addr.type = cp->addr.type;
4053 rp.supported_flags = cpu_to_le32(supported_flags);
4054 rp.current_flags = cpu_to_le32(current_flags);
4055
4056 status = MGMT_STATUS_SUCCESS;
4057
4058done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004059 hci_dev_unlock(hdev);
4060
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004061 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4062 &rp, sizeof(rp));
4063}
4064
4065static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4066 bdaddr_t *bdaddr, u8 bdaddr_type,
4067 u32 supported_flags, u32 current_flags)
4068{
4069 struct mgmt_ev_device_flags_changed ev;
4070
4071 bacpy(&ev.addr.bdaddr, bdaddr);
4072 ev.addr.type = bdaddr_type;
4073 ev.supported_flags = cpu_to_le32(supported_flags);
4074 ev.current_flags = cpu_to_le32(current_flags);
4075
4076 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4077}
4078
4079static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4080 u16 len)
4081{
4082 struct mgmt_cp_set_device_flags *cp = data;
4083 struct bdaddr_list_with_flags *br_params;
4084 struct hci_conn_params *params;
4085 u8 status = MGMT_STATUS_INVALID_PARAMS;
4086 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4087 u32 current_flags = __le32_to_cpu(cp->current_flags);
4088
4089 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4090 &cp->addr.bdaddr, cp->addr.type,
4091 __le32_to_cpu(current_flags));
4092
4093 if ((supported_flags | current_flags) != supported_flags) {
4094 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4095 current_flags, supported_flags);
4096 goto done;
4097 }
4098
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004099 hci_dev_lock(hdev);
4100
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004101 if (cp->addr.type == BDADDR_BREDR) {
4102 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4103 &cp->addr.bdaddr,
4104 cp->addr.type);
4105
4106 if (br_params) {
4107 br_params->current_flags = current_flags;
4108 status = MGMT_STATUS_SUCCESS;
4109 } else {
4110 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4111 &cp->addr.bdaddr, cp->addr.type);
4112 }
4113 } else {
4114 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4115 le_addr_type(cp->addr.type));
4116 if (params) {
4117 params->current_flags = current_flags;
4118 status = MGMT_STATUS_SUCCESS;
4119 } else {
4120 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4121 &cp->addr.bdaddr,
4122 le_addr_type(cp->addr.type));
4123 }
4124 }
4125
4126done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004127 hci_dev_unlock(hdev);
4128
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004129 if (status == MGMT_STATUS_SUCCESS)
4130 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4131 supported_flags, current_flags);
4132
4133 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4134 &cp->addr, sizeof(cp->addr));
4135}
4136
Miao-chen Choub52729f2020-06-17 16:39:16 +02004137static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4138 u16 handle)
4139{
4140 struct mgmt_ev_adv_monitor_added ev;
4141
4142 ev.monitor_handle = cpu_to_le16(handle);
4143
4144 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4145}
4146
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004147static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
4148 u16 handle)
4149{
4150 struct mgmt_ev_adv_monitor_added ev;
4151
4152 ev.monitor_handle = cpu_to_le16(handle);
4153
4154 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
4155}
4156
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004157static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4158 void *data, u16 len)
4159{
4160 struct adv_monitor *monitor = NULL;
4161 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004162 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004163 size_t rp_size = 0;
4164 __u32 supported = 0;
4165 __u16 num_handles = 0;
4166 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4167
4168 BT_DBG("request for %s", hdev->name);
4169
4170 hci_dev_lock(hdev);
4171
4172 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
4173 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4174
4175 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
4176 handles[num_handles++] = monitor->handle;
4177 }
4178
4179 hci_dev_unlock(hdev);
4180
4181 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4182 rp = kmalloc(rp_size, GFP_KERNEL);
4183 if (!rp)
4184 return -ENOMEM;
4185
4186 /* Once controller-based monitoring is in place, the enabled_features
4187 * should reflect the use.
4188 */
4189 rp->supported_features = cpu_to_le32(supported);
4190 rp->enabled_features = 0;
4191 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4192 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4193 rp->num_handles = cpu_to_le16(num_handles);
4194 if (num_handles)
4195 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4196
Peilin Yecafd4722020-09-09 03:25:51 -04004197 err = mgmt_cmd_complete(sk, hdev->id,
4198 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4199 MGMT_STATUS_SUCCESS, rp, rp_size);
4200
4201 kfree(rp);
4202
4203 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004204}
4205
Miao-chen Choub1395532020-06-17 16:39:14 +02004206static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4207 void *data, u16 len)
4208{
4209 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4210 struct mgmt_rp_add_adv_patterns_monitor rp;
4211 struct adv_monitor *m = NULL;
4212 struct adv_pattern *p = NULL;
Miao-chen Choub52729f2020-06-17 16:39:16 +02004213 unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
Miao-chen Choub1395532020-06-17 16:39:14 +02004214 __u8 cp_ofst = 0, cp_len = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004215 int err, i;
4216
4217 BT_DBG("request for %s", hdev->name);
4218
4219 if (len <= sizeof(*cp) || cp->pattern_count == 0) {
4220 err = mgmt_cmd_status(sk, hdev->id,
4221 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4222 MGMT_STATUS_INVALID_PARAMS);
4223 goto failed;
4224 }
4225
4226 m = kmalloc(sizeof(*m), GFP_KERNEL);
4227 if (!m) {
4228 err = -ENOMEM;
4229 goto failed;
4230 }
4231
4232 INIT_LIST_HEAD(&m->patterns);
4233 m->active = false;
4234
4235 for (i = 0; i < cp->pattern_count; i++) {
4236 if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
4237 err = mgmt_cmd_status(sk, hdev->id,
4238 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4239 MGMT_STATUS_INVALID_PARAMS);
4240 goto failed;
4241 }
4242
4243 cp_ofst = cp->patterns[i].offset;
4244 cp_len = cp->patterns[i].length;
4245 if (cp_ofst >= HCI_MAX_AD_LENGTH ||
4246 cp_len > HCI_MAX_AD_LENGTH ||
4247 (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
4248 err = mgmt_cmd_status(sk, hdev->id,
4249 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4250 MGMT_STATUS_INVALID_PARAMS);
4251 goto failed;
4252 }
4253
4254 p = kmalloc(sizeof(*p), GFP_KERNEL);
4255 if (!p) {
4256 err = -ENOMEM;
4257 goto failed;
4258 }
4259
4260 p->ad_type = cp->patterns[i].ad_type;
4261 p->offset = cp->patterns[i].offset;
4262 p->length = cp->patterns[i].length;
4263 memcpy(p->value, cp->patterns[i].value, p->length);
4264
4265 INIT_LIST_HEAD(&p->list);
4266 list_add(&p->list, &m->patterns);
4267 }
4268
4269 if (mp_cnt != cp->pattern_count) {
4270 err = mgmt_cmd_status(sk, hdev->id,
4271 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4272 MGMT_STATUS_INVALID_PARAMS);
4273 goto failed;
4274 }
4275
4276 hci_dev_lock(hdev);
4277
Miao-chen Choub52729f2020-06-17 16:39:16 +02004278 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4279
Miao-chen Choub1395532020-06-17 16:39:14 +02004280 err = hci_add_adv_monitor(hdev, m);
4281 if (err) {
4282 if (err == -ENOSPC) {
4283 mgmt_cmd_status(sk, hdev->id,
4284 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4285 MGMT_STATUS_NO_RESOURCES);
4286 }
4287 goto unlock;
4288 }
4289
Miao-chen Choub52729f2020-06-17 16:39:16 +02004290 if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt)
4291 mgmt_adv_monitor_added(sk, hdev, m->handle);
4292
Miao-chen Choub1395532020-06-17 16:39:14 +02004293 hci_dev_unlock(hdev);
4294
4295 rp.monitor_handle = cpu_to_le16(m->handle);
4296
4297 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4298 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4299
4300unlock:
4301 hci_dev_unlock(hdev);
4302
4303failed:
4304 hci_free_adv_monitor(m);
4305 return err;
4306}
4307
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004308static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4309 void *data, u16 len)
4310{
4311 struct mgmt_cp_remove_adv_monitor *cp = data;
4312 struct mgmt_rp_remove_adv_monitor rp;
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004313 unsigned int prev_adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004314 u16 handle;
4315 int err;
4316
4317 BT_DBG("request for %s", hdev->name);
4318
4319 hci_dev_lock(hdev);
4320
4321 handle = __le16_to_cpu(cp->monitor_handle);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004322 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004323
4324 err = hci_remove_adv_monitor(hdev, handle);
4325 if (err == -ENOENT) {
4326 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4327 MGMT_STATUS_INVALID_INDEX);
4328 goto unlock;
4329 }
4330
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004331 if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt)
4332 mgmt_adv_monitor_removed(sk, hdev, handle);
4333
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004334 hci_dev_unlock(hdev);
4335
4336 rp.monitor_handle = cp->monitor_handle;
4337
4338 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4339 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4340
4341unlock:
4342 hci_dev_unlock(hdev);
4343 return err;
4344}
4345
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004346static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4347 u16 opcode, struct sk_buff *skb)
4348{
4349 struct mgmt_rp_read_local_oob_data mgmt_rp;
4350 size_t rp_size = sizeof(mgmt_rp);
4351 struct mgmt_pending_cmd *cmd;
4352
Marcel Holtmann181d6952020-05-06 09:57:47 +02004353 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004354
4355 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4356 if (!cmd)
4357 return;
4358
4359 if (status || !skb) {
4360 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4361 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4362 goto remove;
4363 }
4364
4365 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4366
4367 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4368 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4369
4370 if (skb->len < sizeof(*rp)) {
4371 mgmt_cmd_status(cmd->sk, hdev->id,
4372 MGMT_OP_READ_LOCAL_OOB_DATA,
4373 MGMT_STATUS_FAILED);
4374 goto remove;
4375 }
4376
4377 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4378 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4379
4380 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4381 } else {
4382 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4383
4384 if (skb->len < sizeof(*rp)) {
4385 mgmt_cmd_status(cmd->sk, hdev->id,
4386 MGMT_OP_READ_LOCAL_OOB_DATA,
4387 MGMT_STATUS_FAILED);
4388 goto remove;
4389 }
4390
4391 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4392 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4393
4394 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4395 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4396 }
4397
4398 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4399 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4400
4401remove:
4402 mgmt_pending_remove(cmd);
4403}
4404
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004405static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004406 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004407{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004408 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004409 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004410 int err;
4411
Marcel Holtmann181d6952020-05-06 09:57:47 +02004412 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004414 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004415
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004416 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4418 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004419 goto unlock;
4420 }
4421
Andre Guedes9a1a1992012-07-24 15:03:48 -03004422 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004423 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4424 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004425 goto unlock;
4426 }
4427
Johan Hedberg333ae952015-03-17 13:48:47 +02004428 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004429 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4430 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004431 goto unlock;
4432 }
4433
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004434 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004435 if (!cmd) {
4436 err = -ENOMEM;
4437 goto unlock;
4438 }
4439
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004440 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004441
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004442 if (bredr_sc_enabled(hdev))
4443 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4444 else
4445 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4446
4447 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004448 if (err < 0)
4449 mgmt_pending_remove(cmd);
4450
4451unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004452 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004453 return err;
4454}
4455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004456static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004457 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004458{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004459 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004460 int err;
4461
Marcel Holtmann181d6952020-05-06 09:57:47 +02004462 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004463
Johan Hedberg5d57e792015-01-23 10:10:38 +02004464 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004465 return mgmt_cmd_complete(sk, hdev->id,
4466 MGMT_OP_ADD_REMOTE_OOB_DATA,
4467 MGMT_STATUS_INVALID_PARAMS,
4468 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004469
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004470 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004471
Marcel Holtmannec109112014-01-10 02:07:30 -08004472 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4473 struct mgmt_cp_add_remote_oob_data *cp = data;
4474 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004475
Johan Hedbergc19a4952014-11-17 20:52:19 +02004476 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004477 err = mgmt_cmd_complete(sk, hdev->id,
4478 MGMT_OP_ADD_REMOTE_OOB_DATA,
4479 MGMT_STATUS_INVALID_PARAMS,
4480 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004481 goto unlock;
4482 }
4483
Marcel Holtmannec109112014-01-10 02:07:30 -08004484 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004485 cp->addr.type, cp->hash,
4486 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004487 if (err < 0)
4488 status = MGMT_STATUS_FAILED;
4489 else
4490 status = MGMT_STATUS_SUCCESS;
4491
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004492 err = mgmt_cmd_complete(sk, hdev->id,
4493 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4494 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004495 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4496 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004497 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004498 u8 status;
4499
Johan Hedberg86df9202014-10-26 20:52:27 +01004500 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004501 /* Enforce zero-valued 192-bit parameters as
4502 * long as legacy SMP OOB isn't implemented.
4503 */
4504 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4505 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004506 err = mgmt_cmd_complete(sk, hdev->id,
4507 MGMT_OP_ADD_REMOTE_OOB_DATA,
4508 MGMT_STATUS_INVALID_PARAMS,
4509 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004510 goto unlock;
4511 }
4512
Johan Hedberg86df9202014-10-26 20:52:27 +01004513 rand192 = NULL;
4514 hash192 = NULL;
4515 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004516 /* In case one of the P-192 values is set to zero,
4517 * then just disable OOB data for P-192.
4518 */
4519 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4520 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4521 rand192 = NULL;
4522 hash192 = NULL;
4523 } else {
4524 rand192 = cp->rand192;
4525 hash192 = cp->hash192;
4526 }
4527 }
4528
4529 /* In case one of the P-256 values is set to zero, then just
4530 * disable OOB data for P-256.
4531 */
4532 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4533 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4534 rand256 = NULL;
4535 hash256 = NULL;
4536 } else {
4537 rand256 = cp->rand256;
4538 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004539 }
4540
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004541 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004542 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004543 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004544 if (err < 0)
4545 status = MGMT_STATUS_FAILED;
4546 else
4547 status = MGMT_STATUS_SUCCESS;
4548
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004549 err = mgmt_cmd_complete(sk, hdev->id,
4550 MGMT_OP_ADD_REMOTE_OOB_DATA,
4551 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004552 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004553 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4554 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004555 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4556 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004557 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004558
Johan Hedbergc19a4952014-11-17 20:52:19 +02004559unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004560 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004561 return err;
4562}
4563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004564static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004565 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004566{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004567 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004568 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004569 int err;
4570
Marcel Holtmann181d6952020-05-06 09:57:47 +02004571 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004572
Johan Hedbergc19a4952014-11-17 20:52:19 +02004573 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004574 return mgmt_cmd_complete(sk, hdev->id,
4575 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4576 MGMT_STATUS_INVALID_PARAMS,
4577 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004579 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004580
Johan Hedbergeedbd582014-11-15 09:34:23 +02004581 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4582 hci_remote_oob_data_clear(hdev);
4583 status = MGMT_STATUS_SUCCESS;
4584 goto done;
4585 }
4586
Johan Hedberg6928a922014-10-26 20:46:09 +01004587 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004588 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004589 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004590 else
Szymon Janca6785be2012-12-13 15:11:21 +01004591 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004592
Johan Hedbergeedbd582014-11-15 09:34:23 +02004593done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004594 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4595 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004597 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004598 return err;
4599}
4600
Johan Hedberge68f0722015-11-11 08:30:30 +02004601void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004602{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004603 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004604
Marcel Holtmann181d6952020-05-06 09:57:47 +02004605 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004606
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004607 hci_dev_lock(hdev);
4608
Johan Hedberg333ae952015-03-17 13:48:47 +02004609 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004610 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004611 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004612
Johan Hedberg78b781c2016-01-05 13:19:32 +02004613 if (!cmd)
4614 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4615
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004616 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004617 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004618 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004619 }
4620
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004621 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004622
4623 /* Handle suspend notifier */
4624 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4625 hdev->suspend_tasks)) {
4626 bt_dev_dbg(hdev, "Unpaused discovery");
4627 wake_up(&hdev->suspend_wait_q);
4628 }
Andre Guedes7c307722013-04-30 15:29:28 -03004629}
4630
Johan Hedberg591752a2015-11-11 08:11:24 +02004631static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4632 uint8_t *mgmt_status)
4633{
4634 switch (type) {
4635 case DISCOV_TYPE_LE:
4636 *mgmt_status = mgmt_le_support(hdev);
4637 if (*mgmt_status)
4638 return false;
4639 break;
4640 case DISCOV_TYPE_INTERLEAVED:
4641 *mgmt_status = mgmt_le_support(hdev);
4642 if (*mgmt_status)
4643 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05004644 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02004645 case DISCOV_TYPE_BREDR:
4646 *mgmt_status = mgmt_bredr_support(hdev);
4647 if (*mgmt_status)
4648 return false;
4649 break;
4650 default:
4651 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4652 return false;
4653 }
4654
4655 return true;
4656}
4657
Johan Hedberg78b781c2016-01-05 13:19:32 +02004658static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4659 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004660{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004661 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004662 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004663 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004664 int err;
4665
Marcel Holtmann181d6952020-05-06 09:57:47 +02004666 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004668 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004669
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004670 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004671 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004672 MGMT_STATUS_NOT_POWERED,
4673 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004674 goto failed;
4675 }
4676
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004677 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004678 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004679 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4680 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004681 goto failed;
4682 }
4683
Johan Hedberg591752a2015-11-11 08:11:24 +02004684 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004685 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4686 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004687 goto failed;
4688 }
4689
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004690 /* Can't start discovery when it is paused */
4691 if (hdev->discovery_paused) {
4692 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4693 &cp->type, sizeof(cp->type));
4694 goto failed;
4695 }
4696
Marcel Holtmann22078802014-12-05 11:45:22 +01004697 /* Clear the discovery filter first to free any previously
4698 * allocated memory for the UUID list.
4699 */
4700 hci_discovery_filter_clear(hdev);
4701
Andre Guedes4aab14e2012-02-17 20:39:36 -03004702 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004703 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004704 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4705 hdev->discovery.limited = true;
4706 else
4707 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004708
Johan Hedberg78b781c2016-01-05 13:19:32 +02004709 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004710 if (!cmd) {
4711 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004712 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004713 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004714
Johan Hedberge68f0722015-11-11 08:30:30 +02004715 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004716
4717 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004718 queue_work(hdev->req_workqueue, &hdev->discov_update);
4719 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004720
4721failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004722 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004723 return err;
4724}
4725
Johan Hedberg78b781c2016-01-05 13:19:32 +02004726static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4727 void *data, u16 len)
4728{
4729 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4730 data, len);
4731}
4732
4733static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4734 void *data, u16 len)
4735{
4736 return start_discovery_internal(sk, hdev,
4737 MGMT_OP_START_LIMITED_DISCOVERY,
4738 data, len);
4739}
4740
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004741static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4742 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004743{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004744 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4745 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004746}
4747
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004748static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4749 void *data, u16 len)
4750{
4751 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004752 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004753 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4754 u16 uuid_count, expected_len;
4755 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004756 int err;
4757
Marcel Holtmann181d6952020-05-06 09:57:47 +02004758 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004759
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004760 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004761
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004762 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004763 err = mgmt_cmd_complete(sk, hdev->id,
4764 MGMT_OP_START_SERVICE_DISCOVERY,
4765 MGMT_STATUS_NOT_POWERED,
4766 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004767 goto failed;
4768 }
4769
4770 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004771 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004772 err = mgmt_cmd_complete(sk, hdev->id,
4773 MGMT_OP_START_SERVICE_DISCOVERY,
4774 MGMT_STATUS_BUSY, &cp->type,
4775 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004776 goto failed;
4777 }
4778
4779 uuid_count = __le16_to_cpu(cp->uuid_count);
4780 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004781 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4782 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004783 err = mgmt_cmd_complete(sk, hdev->id,
4784 MGMT_OP_START_SERVICE_DISCOVERY,
4785 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4786 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004787 goto failed;
4788 }
4789
4790 expected_len = sizeof(*cp) + uuid_count * 16;
4791 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004792 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4793 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004794 err = mgmt_cmd_complete(sk, hdev->id,
4795 MGMT_OP_START_SERVICE_DISCOVERY,
4796 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4797 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004798 goto failed;
4799 }
4800
Johan Hedberg591752a2015-11-11 08:11:24 +02004801 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4802 err = mgmt_cmd_complete(sk, hdev->id,
4803 MGMT_OP_START_SERVICE_DISCOVERY,
4804 status, &cp->type, sizeof(cp->type));
4805 goto failed;
4806 }
4807
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004808 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004809 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004810 if (!cmd) {
4811 err = -ENOMEM;
4812 goto failed;
4813 }
4814
Johan Hedberg2922a942014-12-05 13:36:06 +02004815 cmd->cmd_complete = service_discovery_cmd_complete;
4816
Marcel Holtmann22078802014-12-05 11:45:22 +01004817 /* Clear the discovery filter first to free any previously
4818 * allocated memory for the UUID list.
4819 */
4820 hci_discovery_filter_clear(hdev);
4821
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004822 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004823 hdev->discovery.type = cp->type;
4824 hdev->discovery.rssi = cp->rssi;
4825 hdev->discovery.uuid_count = uuid_count;
4826
4827 if (uuid_count > 0) {
4828 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4829 GFP_KERNEL);
4830 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004831 err = mgmt_cmd_complete(sk, hdev->id,
4832 MGMT_OP_START_SERVICE_DISCOVERY,
4833 MGMT_STATUS_FAILED,
4834 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004835 mgmt_pending_remove(cmd);
4836 goto failed;
4837 }
4838 }
4839
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004840 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004841 queue_work(hdev->req_workqueue, &hdev->discov_update);
4842 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004843
4844failed:
4845 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004846 return err;
4847}
4848
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004849void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004850{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004851 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004852
Marcel Holtmann181d6952020-05-06 09:57:47 +02004853 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004854
4855 hci_dev_lock(hdev);
4856
Johan Hedberg333ae952015-03-17 13:48:47 +02004857 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004858 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004859 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004860 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004861 }
4862
Andre Guedes0e05bba2013-04-30 15:29:33 -03004863 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004864
4865 /* Handle suspend notifier */
4866 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4867 bt_dev_dbg(hdev, "Paused discovery");
4868 wake_up(&hdev->suspend_wait_q);
4869 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004870}
4871
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004872static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004873 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004874{
Johan Hedbergd9306502012-02-20 23:25:18 +02004875 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004876 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004877 int err;
4878
Marcel Holtmann181d6952020-05-06 09:57:47 +02004879 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004881 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004882
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004883 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004884 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4885 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4886 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004887 goto unlock;
4888 }
4889
4890 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004891 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4892 MGMT_STATUS_INVALID_PARAMS,
4893 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004894 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004895 }
4896
Johan Hedberg2922a942014-12-05 13:36:06 +02004897 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004898 if (!cmd) {
4899 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004900 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004901 }
4902
Johan Hedberg2922a942014-12-05 13:36:06 +02004903 cmd->cmd_complete = generic_cmd_complete;
4904
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004905 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4906 queue_work(hdev->req_workqueue, &hdev->discov_update);
4907 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004908
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004909unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004910 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004911 return err;
4912}
4913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004914static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004915 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004916{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004917 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004918 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004919 int err;
4920
Marcel Holtmann181d6952020-05-06 09:57:47 +02004921 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004922
Johan Hedberg561aafb2012-01-04 13:31:59 +02004923 hci_dev_lock(hdev);
4924
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004925 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004926 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4927 MGMT_STATUS_FAILED, &cp->addr,
4928 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004929 goto failed;
4930 }
4931
Johan Hedberga198e7b2012-02-17 14:27:06 +02004932 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004933 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004934 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4935 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4936 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004937 goto failed;
4938 }
4939
4940 if (cp->name_known) {
4941 e->name_state = NAME_KNOWN;
4942 list_del(&e->list);
4943 } else {
4944 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004945 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004946 }
4947
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004948 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4949 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004950
4951failed:
4952 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004953 return err;
4954}
4955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004956static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004957 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004958{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004959 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004960 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004961 int err;
4962
Marcel Holtmann181d6952020-05-06 09:57:47 +02004963 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004964
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004965 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004966 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4967 MGMT_STATUS_INVALID_PARAMS,
4968 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004969
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004970 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004971
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004972 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4973 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004974 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004975 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004976 goto done;
4977 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004978
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004979 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4980 sk);
4981 status = MGMT_STATUS_SUCCESS;
4982
4983done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004984 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4985 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004986
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004987 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004988
4989 return err;
4990}
4991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004992static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004993 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004994{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004995 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004996 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004997 int err;
4998
Marcel Holtmann181d6952020-05-06 09:57:47 +02004999 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005000
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005001 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005002 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5003 MGMT_STATUS_INVALID_PARAMS,
5004 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005006 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005007
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005008 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
5009 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005010 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005011 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005012 goto done;
5013 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005014
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005015 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5016 sk);
5017 status = MGMT_STATUS_SUCCESS;
5018
5019done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005020 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5021 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005023 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005024
5025 return err;
5026}
5027
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005028static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5029 u16 len)
5030{
5031 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05005032 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005033 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005034 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005035
Marcel Holtmann181d6952020-05-06 09:57:47 +02005036 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005037
Szymon Jancc72d4b82012-03-16 16:02:57 +01005038 source = __le16_to_cpu(cp->source);
5039
5040 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005041 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5042 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005043
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005044 hci_dev_lock(hdev);
5045
Szymon Jancc72d4b82012-03-16 16:02:57 +01005046 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005047 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5048 hdev->devid_product = __le16_to_cpu(cp->product);
5049 hdev->devid_version = __le16_to_cpu(cp->version);
5050
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005051 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5052 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005053
Johan Hedberg890ea892013-03-15 17:06:52 -05005054 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02005055 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05005056 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005057
5058 hci_dev_unlock(hdev);
5059
5060 return err;
5061}
5062
Arman Uguray24b4f382015-03-23 15:57:12 -07005063static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5064 u16 opcode)
5065{
Marcel Holtmann181d6952020-05-06 09:57:47 +02005066 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005067}
5068
Marcel Holtmann1904a852015-01-11 13:50:44 -08005069static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5070 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005071{
5072 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005073 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005074 u8 instance;
5075 struct adv_info *adv_instance;
5076 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005077
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305078 hci_dev_lock(hdev);
5079
Johan Hedberg4375f102013-09-25 13:26:10 +03005080 if (status) {
5081 u8 mgmt_err = mgmt_status(status);
5082
5083 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5084 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305085 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005086 }
5087
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005088 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005089 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005090 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005091 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005092
Johan Hedberg4375f102013-09-25 13:26:10 +03005093 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5094 &match);
5095
5096 new_settings(hdev, match.sk);
5097
5098 if (match.sk)
5099 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305100
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005101 /* Handle suspend notifier */
5102 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5103 hdev->suspend_tasks)) {
5104 bt_dev_dbg(hdev, "Paused advertising");
5105 wake_up(&hdev->suspend_wait_q);
5106 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5107 hdev->suspend_tasks)) {
5108 bt_dev_dbg(hdev, "Unpaused advertising");
5109 wake_up(&hdev->suspend_wait_q);
5110 }
5111
Arman Uguray24b4f382015-03-23 15:57:12 -07005112 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005113 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005114 */
5115 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005116 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005117 goto unlock;
5118
Florian Grandel7816b822015-06-18 03:16:45 +02005119 instance = hdev->cur_adv_instance;
5120 if (!instance) {
5121 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5122 struct adv_info, list);
5123 if (!adv_instance)
5124 goto unlock;
5125
5126 instance = adv_instance->instance;
5127 }
5128
Arman Uguray24b4f382015-03-23 15:57:12 -07005129 hci_req_init(&req, hdev);
5130
Johan Hedbergf2252572015-11-18 12:49:20 +02005131 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005132
Florian Grandel7816b822015-06-18 03:16:45 +02005133 if (!err)
5134 err = hci_req_run(&req, enable_advertising_instance);
5135
5136 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005137 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005138
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305139unlock:
5140 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005141}
5142
Marcel Holtmann21b51872013-10-10 09:47:53 -07005143static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5144 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005145{
5146 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005147 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005148 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005149 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005150 int err;
5151
Marcel Holtmann181d6952020-05-06 09:57:47 +02005152 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005153
Johan Hedberge6fe7982013-10-02 15:45:22 +03005154 status = mgmt_le_support(hdev);
5155 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005156 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5157 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005158
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05305159 /* Enabling the experimental LL Privay support disables support for
5160 * advertising.
5161 */
5162 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
5163 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5164 MGMT_STATUS_NOT_SUPPORTED);
5165
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005166 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005167 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5168 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005169
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005170 if (hdev->advertising_paused)
5171 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5172 MGMT_STATUS_BUSY);
5173
Johan Hedberg4375f102013-09-25 13:26:10 +03005174 hci_dev_lock(hdev);
5175
5176 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005177
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005178 /* The following conditions are ones which mean that we should
5179 * not do any HCI communication but directly send a mgmt
5180 * response to user space (after toggling the flag if
5181 * necessary).
5182 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005183 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005184 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5185 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005186 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005187 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005188 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005189 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005190
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005191 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005192 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005193 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005194 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005195 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005196 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005197 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005198 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005199 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005200 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005201 }
5202
5203 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5204 if (err < 0)
5205 goto unlock;
5206
5207 if (changed)
5208 err = new_settings(hdev, sk);
5209
5210 goto unlock;
5211 }
5212
Johan Hedberg333ae952015-03-17 13:48:47 +02005213 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5214 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005215 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5216 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005217 goto unlock;
5218 }
5219
5220 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5221 if (!cmd) {
5222 err = -ENOMEM;
5223 goto unlock;
5224 }
5225
5226 hci_req_init(&req, hdev);
5227
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005228 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005229 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005230 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005231 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005232
Florian Grandel7816b822015-06-18 03:16:45 +02005233 cancel_adv_timeout(hdev);
5234
Arman Uguray24b4f382015-03-23 15:57:12 -07005235 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005236 /* Switch to instance "0" for the Set Advertising setting.
5237 * We cannot use update_[adv|scan_rsp]_data() here as the
5238 * HCI_ADVERTISING flag is not yet set.
5239 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005240 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305241
5242 if (ext_adv_capable(hdev)) {
5243 __hci_req_start_ext_adv(&req, 0x00);
5244 } else {
5245 __hci_req_update_adv_data(&req, 0x00);
5246 __hci_req_update_scan_rsp_data(&req, 0x00);
5247 __hci_req_enable_advertising(&req);
5248 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005249 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005250 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005251 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005252
5253 err = hci_req_run(&req, set_advertising_complete);
5254 if (err < 0)
5255 mgmt_pending_remove(cmd);
5256
5257unlock:
5258 hci_dev_unlock(hdev);
5259 return err;
5260}
5261
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005262static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5263 void *data, u16 len)
5264{
5265 struct mgmt_cp_set_static_address *cp = data;
5266 int err;
5267
Marcel Holtmann181d6952020-05-06 09:57:47 +02005268 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005269
Marcel Holtmann62af4442013-10-02 22:10:32 -07005270 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005271 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5272 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005273
5274 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005275 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5276 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005277
5278 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5279 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005280 return mgmt_cmd_status(sk, hdev->id,
5281 MGMT_OP_SET_STATIC_ADDRESS,
5282 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005283
5284 /* Two most significant bits shall be set */
5285 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005286 return mgmt_cmd_status(sk, hdev->id,
5287 MGMT_OP_SET_STATIC_ADDRESS,
5288 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005289 }
5290
5291 hci_dev_lock(hdev);
5292
5293 bacpy(&hdev->static_addr, &cp->bdaddr);
5294
Marcel Holtmann93690c22015-03-06 10:11:21 -08005295 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5296 if (err < 0)
5297 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005298
Marcel Holtmann93690c22015-03-06 10:11:21 -08005299 err = new_settings(hdev, sk);
5300
5301unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005302 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005303 return err;
5304}
5305
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005306static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5307 void *data, u16 len)
5308{
5309 struct mgmt_cp_set_scan_params *cp = data;
5310 __u16 interval, window;
5311 int err;
5312
Marcel Holtmann181d6952020-05-06 09:57:47 +02005313 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005314
5315 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005316 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5317 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005318
5319 interval = __le16_to_cpu(cp->interval);
5320
5321 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005322 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5323 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005324
5325 window = __le16_to_cpu(cp->window);
5326
5327 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5329 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005330
Marcel Holtmann899e1072013-10-14 09:55:32 -07005331 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005332 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5333 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005334
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005335 hci_dev_lock(hdev);
5336
5337 hdev->le_scan_interval = interval;
5338 hdev->le_scan_window = window;
5339
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005340 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5341 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005342
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005343 /* If background scan is running, restart it so new parameters are
5344 * loaded.
5345 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005346 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005347 hdev->discovery.state == DISCOVERY_STOPPED) {
5348 struct hci_request req;
5349
5350 hci_req_init(&req, hdev);
5351
Sathish Narasimman5c49bcc2020-07-23 18:09:01 +05305352 hci_req_add_le_scan_disable(&req, false);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005353 hci_req_add_le_passive_scan(&req);
5354
5355 hci_req_run(&req, NULL);
5356 }
5357
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005358 hci_dev_unlock(hdev);
5359
5360 return err;
5361}
5362
Marcel Holtmann1904a852015-01-11 13:50:44 -08005363static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5364 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005365{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005366 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005367
Marcel Holtmann181d6952020-05-06 09:57:47 +02005368 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005369
5370 hci_dev_lock(hdev);
5371
Johan Hedberg333ae952015-03-17 13:48:47 +02005372 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005373 if (!cmd)
5374 goto unlock;
5375
5376 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005377 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5378 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005379 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005380 struct mgmt_mode *cp = cmd->param;
5381
5382 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005383 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005384 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005385 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005386
Johan Hedberg33e38b32013-03-15 17:07:05 -05005387 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5388 new_settings(hdev, cmd->sk);
5389 }
5390
5391 mgmt_pending_remove(cmd);
5392
5393unlock:
5394 hci_dev_unlock(hdev);
5395}
5396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005397static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005398 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005399{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005400 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005401 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005402 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005403 int err;
5404
Marcel Holtmann181d6952020-05-06 09:57:47 +02005405 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005406
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005407 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005408 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5410 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005411
Johan Hedberga7e80f22013-01-09 16:05:19 +02005412 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005413 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5414 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005415
Antti Julkuf6422ec2011-06-22 13:11:56 +03005416 hci_dev_lock(hdev);
5417
Johan Hedberg333ae952015-03-17 13:48:47 +02005418 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005419 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5420 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005421 goto unlock;
5422 }
5423
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005424 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005425 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5426 hdev);
5427 goto unlock;
5428 }
5429
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005430 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005431 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005432 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5433 hdev);
5434 new_settings(hdev, sk);
5435 goto unlock;
5436 }
5437
Johan Hedberg33e38b32013-03-15 17:07:05 -05005438 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5439 data, len);
5440 if (!cmd) {
5441 err = -ENOMEM;
5442 goto unlock;
5443 }
5444
5445 hci_req_init(&req, hdev);
5446
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005447 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005448
5449 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005450 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005451 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5452 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005453 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005454 }
5455
Johan Hedberg33e38b32013-03-15 17:07:05 -05005456unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005457 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005458
Antti Julkuf6422ec2011-06-22 13:11:56 +03005459 return err;
5460}
5461
Marcel Holtmann1904a852015-01-11 13:50:44 -08005462static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005463{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005464 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005465
Marcel Holtmann181d6952020-05-06 09:57:47 +02005466 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005467
5468 hci_dev_lock(hdev);
5469
Johan Hedberg333ae952015-03-17 13:48:47 +02005470 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005471 if (!cmd)
5472 goto unlock;
5473
5474 if (status) {
5475 u8 mgmt_err = mgmt_status(status);
5476
5477 /* We need to restore the flag if related HCI commands
5478 * failed.
5479 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005480 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005481
Johan Hedberga69e8372015-03-06 21:08:53 +02005482 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005483 } else {
5484 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5485 new_settings(hdev, cmd->sk);
5486 }
5487
5488 mgmt_pending_remove(cmd);
5489
5490unlock:
5491 hci_dev_unlock(hdev);
5492}
5493
5494static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5495{
5496 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005497 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005498 struct hci_request req;
5499 int err;
5500
Marcel Holtmann181d6952020-05-06 09:57:47 +02005501 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005502
5503 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005504 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5505 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005506
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005507 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005508 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5509 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005510
5511 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005512 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005514
5515 hci_dev_lock(hdev);
5516
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005517 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005518 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5519 goto unlock;
5520 }
5521
5522 if (!hdev_is_powered(hdev)) {
5523 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005524 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5525 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5526 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5527 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5528 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005529 }
5530
Marcel Holtmannce05d602015-03-13 02:11:03 -07005531 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005532
5533 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5534 if (err < 0)
5535 goto unlock;
5536
5537 err = new_settings(hdev, sk);
5538 goto unlock;
5539 }
5540
5541 /* Reject disabling when powered on */
5542 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005543 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5544 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005545 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005546 } else {
5547 /* When configuring a dual-mode controller to operate
5548 * with LE only and using a static address, then switching
5549 * BR/EDR back on is not allowed.
5550 *
5551 * Dual-mode controllers shall operate with the public
5552 * address as its identity address for BR/EDR and LE. So
5553 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005554 *
5555 * The same restrictions applies when secure connections
5556 * has been enabled. For BR/EDR this is a controller feature
5557 * while for LE it is a host stack feature. This means that
5558 * switching BR/EDR back on when secure connections has been
5559 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005560 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005561 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005562 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005563 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005564 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5565 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005566 goto unlock;
5567 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005568 }
5569
Johan Hedberg333ae952015-03-17 13:48:47 +02005570 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005571 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5572 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005573 goto unlock;
5574 }
5575
5576 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5577 if (!cmd) {
5578 err = -ENOMEM;
5579 goto unlock;
5580 }
5581
Johan Hedbergf2252572015-11-18 12:49:20 +02005582 /* We need to flip the bit already here so that
5583 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005584 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005585 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005586
5587 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005588
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005589 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005590 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005591
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005592 /* Since only the advertising data flags will change, there
5593 * is no need to update the scan response data.
5594 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005595 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005596
Johan Hedberg0663ca22013-10-02 13:43:14 +03005597 err = hci_req_run(&req, set_bredr_complete);
5598 if (err < 0)
5599 mgmt_pending_remove(cmd);
5600
5601unlock:
5602 hci_dev_unlock(hdev);
5603 return err;
5604}
5605
Johan Hedberga1443f52015-01-23 15:42:46 +02005606static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5607{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005608 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005609 struct mgmt_mode *cp;
5610
Marcel Holtmann181d6952020-05-06 09:57:47 +02005611 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005612
5613 hci_dev_lock(hdev);
5614
Johan Hedberg333ae952015-03-17 13:48:47 +02005615 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005616 if (!cmd)
5617 goto unlock;
5618
5619 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005620 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5621 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005622 goto remove;
5623 }
5624
5625 cp = cmd->param;
5626
5627 switch (cp->val) {
5628 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005629 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5630 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005631 break;
5632 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005633 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005634 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005635 break;
5636 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005637 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5638 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005639 break;
5640 }
5641
5642 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5643 new_settings(hdev, cmd->sk);
5644
5645remove:
5646 mgmt_pending_remove(cmd);
5647unlock:
5648 hci_dev_unlock(hdev);
5649}
5650
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005651static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5652 void *data, u16 len)
5653{
5654 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005655 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005656 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005657 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005658 int err;
5659
Marcel Holtmann181d6952020-05-06 09:57:47 +02005660 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005661
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005662 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005663 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5665 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005667 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005668 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005669 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5671 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005672
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005673 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005675 MGMT_STATUS_INVALID_PARAMS);
5676
5677 hci_dev_lock(hdev);
5678
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005679 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005680 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005681 bool changed;
5682
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005683 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005684 changed = !hci_dev_test_and_set_flag(hdev,
5685 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005686 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005687 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005688 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005689 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005690 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005691 changed = hci_dev_test_and_clear_flag(hdev,
5692 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005693 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005694 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005695
5696 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5697 if (err < 0)
5698 goto failed;
5699
5700 if (changed)
5701 err = new_settings(hdev, sk);
5702
5703 goto failed;
5704 }
5705
Johan Hedberg333ae952015-03-17 13:48:47 +02005706 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005707 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5708 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005709 goto failed;
5710 }
5711
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005712 val = !!cp->val;
5713
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005714 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5715 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005716 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5717 goto failed;
5718 }
5719
5720 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5721 if (!cmd) {
5722 err = -ENOMEM;
5723 goto failed;
5724 }
5725
Johan Hedberga1443f52015-01-23 15:42:46 +02005726 hci_req_init(&req, hdev);
5727 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5728 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005729 if (err < 0) {
5730 mgmt_pending_remove(cmd);
5731 goto failed;
5732 }
5733
5734failed:
5735 hci_dev_unlock(hdev);
5736 return err;
5737}
5738
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005739static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5740 void *data, u16 len)
5741{
5742 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005743 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005744 int err;
5745
Marcel Holtmann181d6952020-05-06 09:57:47 +02005746 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005747
Johan Hedbergb97109792014-06-24 14:00:28 +03005748 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005749 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5750 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005751
5752 hci_dev_lock(hdev);
5753
5754 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005755 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005756 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005757 changed = hci_dev_test_and_clear_flag(hdev,
5758 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005759
Johan Hedbergb97109792014-06-24 14:00:28 +03005760 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005761 use_changed = !hci_dev_test_and_set_flag(hdev,
5762 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005763 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005764 use_changed = hci_dev_test_and_clear_flag(hdev,
5765 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005766
5767 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005768 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005769 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5770 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5771 sizeof(mode), &mode);
5772 }
5773
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005774 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5775 if (err < 0)
5776 goto unlock;
5777
5778 if (changed)
5779 err = new_settings(hdev, sk);
5780
5781unlock:
5782 hci_dev_unlock(hdev);
5783 return err;
5784}
5785
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005786static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5787 u16 len)
5788{
5789 struct mgmt_cp_set_privacy *cp = cp_data;
5790 bool changed;
5791 int err;
5792
Marcel Holtmann181d6952020-05-06 09:57:47 +02005793 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005794
5795 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005796 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5797 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005798
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005799 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005800 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5801 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005802
5803 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005804 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5805 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005806
5807 hci_dev_lock(hdev);
5808
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005809 /* If user space supports this command it is also expected to
5810 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5811 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005812 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005813
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005814 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005815 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005816 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005817 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305818 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005819 if (cp->privacy == 0x02)
5820 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5821 else
5822 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005823 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005824 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005825 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005826 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305827 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005828 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005829 }
5830
5831 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5832 if (err < 0)
5833 goto unlock;
5834
5835 if (changed)
5836 err = new_settings(hdev, sk);
5837
5838unlock:
5839 hci_dev_unlock(hdev);
5840 return err;
5841}
5842
Johan Hedberg41edf162014-02-18 10:19:35 +02005843static bool irk_is_valid(struct mgmt_irk_info *irk)
5844{
5845 switch (irk->addr.type) {
5846 case BDADDR_LE_PUBLIC:
5847 return true;
5848
5849 case BDADDR_LE_RANDOM:
5850 /* Two most significant bits shall be set */
5851 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5852 return false;
5853 return true;
5854 }
5855
5856 return false;
5857}
5858
5859static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5860 u16 len)
5861{
5862 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005863 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5864 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005865 u16 irk_count, expected_len;
5866 int i, err;
5867
Marcel Holtmann181d6952020-05-06 09:57:47 +02005868 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005869
5870 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005871 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5872 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005873
5874 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005875 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005876 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5877 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005878 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005880 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005881
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005882 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005883 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005884 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5885 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005886 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5887 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005888 }
5889
Marcel Holtmann181d6952020-05-06 09:57:47 +02005890 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005891
5892 for (i = 0; i < irk_count; i++) {
5893 struct mgmt_irk_info *key = &cp->irks[i];
5894
5895 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005896 return mgmt_cmd_status(sk, hdev->id,
5897 MGMT_OP_LOAD_IRKS,
5898 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005899 }
5900
5901 hci_dev_lock(hdev);
5902
5903 hci_smp_irks_clear(hdev);
5904
5905 for (i = 0; i < irk_count; i++) {
5906 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005907
Alain Michaud600a8742020-01-07 00:43:17 +00005908 if (hci_is_blocked_key(hdev,
5909 HCI_BLOCKED_KEY_TYPE_IRK,
5910 irk->val)) {
5911 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5912 &irk->addr.bdaddr);
5913 continue;
5914 }
5915
Johan Hedberg85813a72015-10-21 18:02:59 +03005916 hci_add_irk(hdev, &irk->addr.bdaddr,
5917 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005918 BDADDR_ANY);
5919 }
5920
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005921 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005922
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005923 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005924
5925 hci_dev_unlock(hdev);
5926
5927 return err;
5928}
5929
Johan Hedberg3f706b72013-01-20 14:27:16 +02005930static bool ltk_is_valid(struct mgmt_ltk_info *key)
5931{
5932 if (key->master != 0x00 && key->master != 0x01)
5933 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005934
5935 switch (key->addr.type) {
5936 case BDADDR_LE_PUBLIC:
5937 return true;
5938
5939 case BDADDR_LE_RANDOM:
5940 /* Two most significant bits shall be set */
5941 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5942 return false;
5943 return true;
5944 }
5945
5946 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005947}
5948
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005949static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005950 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005951{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005952 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005953 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5954 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005955 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005956 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005957
Marcel Holtmann181d6952020-05-06 09:57:47 +02005958 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005959
5960 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005961 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5962 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005963
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005964 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005965 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005966 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5967 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005968 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5969 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005970 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005971
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005972 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005973 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005974 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5975 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005976 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5977 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005978 }
5979
Marcel Holtmann181d6952020-05-06 09:57:47 +02005980 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005981
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005982 for (i = 0; i < key_count; i++) {
5983 struct mgmt_ltk_info *key = &cp->keys[i];
5984
Johan Hedberg3f706b72013-01-20 14:27:16 +02005985 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005986 return mgmt_cmd_status(sk, hdev->id,
5987 MGMT_OP_LOAD_LONG_TERM_KEYS,
5988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005989 }
5990
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005991 hci_dev_lock(hdev);
5992
5993 hci_smp_ltks_clear(hdev);
5994
5995 for (i = 0; i < key_count; i++) {
5996 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005997 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005998
Alain Michaud600a8742020-01-07 00:43:17 +00005999 if (hci_is_blocked_key(hdev,
6000 HCI_BLOCKED_KEY_TYPE_LTK,
6001 key->val)) {
6002 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6003 &key->addr.bdaddr);
6004 continue;
6005 }
6006
Johan Hedberg61b43352014-05-29 19:36:53 +03006007 switch (key->type) {
6008 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006009 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006010 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006011 break;
6012 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006013 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006014 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006015 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006016 case MGMT_LTK_P256_UNAUTH:
6017 authenticated = 0x00;
6018 type = SMP_LTK_P256;
6019 break;
6020 case MGMT_LTK_P256_AUTH:
6021 authenticated = 0x01;
6022 type = SMP_LTK_P256;
6023 break;
6024 case MGMT_LTK_P256_DEBUG:
6025 authenticated = 0x00;
6026 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006027 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006028 default:
6029 continue;
6030 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006031
Johan Hedberg85813a72015-10-21 18:02:59 +03006032 hci_add_ltk(hdev, &key->addr.bdaddr,
6033 le_addr_type(key->addr.type), type, authenticated,
6034 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006035 }
6036
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006037 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006038 NULL, 0);
6039
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006040 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006041
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006042 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006043}
6044
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006045static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006046{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006047 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006048 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006049 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006050
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006051 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006052
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006053 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006054 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006055 rp.tx_power = conn->tx_power;
6056 rp.max_tx_power = conn->max_tx_power;
6057 } else {
6058 rp.rssi = HCI_RSSI_INVALID;
6059 rp.tx_power = HCI_TX_POWER_INVALID;
6060 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006061 }
6062
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006063 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6064 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006065
6066 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006067 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006068
6069 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006070}
6071
Marcel Holtmann1904a852015-01-11 13:50:44 -08006072static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6073 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006074{
6075 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006076 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006077 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006078 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006079 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006080
Marcel Holtmann181d6952020-05-06 09:57:47 +02006081 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006082
6083 hci_dev_lock(hdev);
6084
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006085 /* Commands sent in request are either Read RSSI or Read Transmit Power
6086 * Level so we check which one was last sent to retrieve connection
6087 * handle. Both commands have handle as first parameter so it's safe to
6088 * cast data on the same command struct.
6089 *
6090 * First command sent is always Read RSSI and we fail only if it fails.
6091 * In other case we simply override error to indicate success as we
6092 * already remembered if TX power value is actually valid.
6093 */
6094 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6095 if (!cp) {
6096 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006097 status = MGMT_STATUS_SUCCESS;
6098 } else {
6099 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006100 }
6101
6102 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006103 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006104 goto unlock;
6105 }
6106
6107 handle = __le16_to_cpu(cp->handle);
6108 conn = hci_conn_hash_lookup_handle(hdev, handle);
6109 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006110 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
6111 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006112 goto unlock;
6113 }
6114
Johan Hedberg333ae952015-03-17 13:48:47 +02006115 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006116 if (!cmd)
6117 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006118
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006119 cmd->cmd_complete(cmd, status);
6120 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006121
6122unlock:
6123 hci_dev_unlock(hdev);
6124}
6125
6126static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6127 u16 len)
6128{
6129 struct mgmt_cp_get_conn_info *cp = data;
6130 struct mgmt_rp_get_conn_info rp;
6131 struct hci_conn *conn;
6132 unsigned long conn_info_age;
6133 int err = 0;
6134
Marcel Holtmann181d6952020-05-06 09:57:47 +02006135 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006136
6137 memset(&rp, 0, sizeof(rp));
6138 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6139 rp.addr.type = cp->addr.type;
6140
6141 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006142 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6143 MGMT_STATUS_INVALID_PARAMS,
6144 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006145
6146 hci_dev_lock(hdev);
6147
6148 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006149 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6150 MGMT_STATUS_NOT_POWERED, &rp,
6151 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006152 goto unlock;
6153 }
6154
6155 if (cp->addr.type == BDADDR_BREDR)
6156 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6157 &cp->addr.bdaddr);
6158 else
6159 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6160
6161 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006162 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6163 MGMT_STATUS_NOT_CONNECTED, &rp,
6164 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006165 goto unlock;
6166 }
6167
Johan Hedberg333ae952015-03-17 13:48:47 +02006168 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006169 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6170 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006171 goto unlock;
6172 }
6173
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006174 /* To avoid client trying to guess when to poll again for information we
6175 * calculate conn info age as random value between min/max set in hdev.
6176 */
6177 conn_info_age = hdev->conn_info_min_age +
6178 prandom_u32_max(hdev->conn_info_max_age -
6179 hdev->conn_info_min_age);
6180
6181 /* Query controller to refresh cached values if they are too old or were
6182 * never read.
6183 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006184 if (time_after(jiffies, conn->conn_info_timestamp +
6185 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006186 !conn->conn_info_timestamp) {
6187 struct hci_request req;
6188 struct hci_cp_read_tx_power req_txp_cp;
6189 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006190 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006191
6192 hci_req_init(&req, hdev);
6193 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6194 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6195 &req_rssi_cp);
6196
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006197 /* For LE links TX power does not change thus we don't need to
6198 * query for it once value is known.
6199 */
6200 if (!bdaddr_type_is_le(cp->addr.type) ||
6201 conn->tx_power == HCI_TX_POWER_INVALID) {
6202 req_txp_cp.handle = cpu_to_le16(conn->handle);
6203 req_txp_cp.type = 0x00;
6204 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6205 sizeof(req_txp_cp), &req_txp_cp);
6206 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006207
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006208 /* Max TX power needs to be read only once per connection */
6209 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6210 req_txp_cp.handle = cpu_to_le16(conn->handle);
6211 req_txp_cp.type = 0x01;
6212 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6213 sizeof(req_txp_cp), &req_txp_cp);
6214 }
6215
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006216 err = hci_req_run(&req, conn_info_refresh_complete);
6217 if (err < 0)
6218 goto unlock;
6219
6220 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6221 data, len);
6222 if (!cmd) {
6223 err = -ENOMEM;
6224 goto unlock;
6225 }
6226
6227 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006228 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006229 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006230
6231 conn->conn_info_timestamp = jiffies;
6232 } else {
6233 /* Cache is valid, just reply with values cached in hci_conn */
6234 rp.rssi = conn->rssi;
6235 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006236 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006237
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006238 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6239 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006240 }
6241
6242unlock:
6243 hci_dev_unlock(hdev);
6244 return err;
6245}
6246
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006247static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006248{
6249 struct hci_conn *conn = cmd->user_data;
6250 struct mgmt_rp_get_clock_info rp;
6251 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006252 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006253
6254 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006255 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006256
6257 if (status)
6258 goto complete;
6259
6260 hdev = hci_dev_get(cmd->index);
6261 if (hdev) {
6262 rp.local_clock = cpu_to_le32(hdev->clock);
6263 hci_dev_put(hdev);
6264 }
6265
6266 if (conn) {
6267 rp.piconet_clock = cpu_to_le32(conn->clock);
6268 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6269 }
6270
6271complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006272 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6273 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006274
6275 if (conn) {
6276 hci_conn_drop(conn);
6277 hci_conn_put(conn);
6278 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006279
6280 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006281}
6282
Marcel Holtmann1904a852015-01-11 13:50:44 -08006283static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006284{
Johan Hedberg95868422014-06-28 17:54:07 +03006285 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006286 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006287 struct hci_conn *conn;
6288
Marcel Holtmann181d6952020-05-06 09:57:47 +02006289 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006290
6291 hci_dev_lock(hdev);
6292
6293 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6294 if (!hci_cp)
6295 goto unlock;
6296
6297 if (hci_cp->which) {
6298 u16 handle = __le16_to_cpu(hci_cp->handle);
6299 conn = hci_conn_hash_lookup_handle(hdev, handle);
6300 } else {
6301 conn = NULL;
6302 }
6303
Johan Hedberg333ae952015-03-17 13:48:47 +02006304 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006305 if (!cmd)
6306 goto unlock;
6307
Johan Hedberg69487372014-12-05 13:36:07 +02006308 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006309 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006310
6311unlock:
6312 hci_dev_unlock(hdev);
6313}
6314
6315static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6316 u16 len)
6317{
6318 struct mgmt_cp_get_clock_info *cp = data;
6319 struct mgmt_rp_get_clock_info rp;
6320 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006321 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006322 struct hci_request req;
6323 struct hci_conn *conn;
6324 int err;
6325
Marcel Holtmann181d6952020-05-06 09:57:47 +02006326 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006327
6328 memset(&rp, 0, sizeof(rp));
6329 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6330 rp.addr.type = cp->addr.type;
6331
6332 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006333 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6334 MGMT_STATUS_INVALID_PARAMS,
6335 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006336
6337 hci_dev_lock(hdev);
6338
6339 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006340 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6341 MGMT_STATUS_NOT_POWERED, &rp,
6342 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006343 goto unlock;
6344 }
6345
6346 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6347 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6348 &cp->addr.bdaddr);
6349 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006350 err = mgmt_cmd_complete(sk, hdev->id,
6351 MGMT_OP_GET_CLOCK_INFO,
6352 MGMT_STATUS_NOT_CONNECTED,
6353 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006354 goto unlock;
6355 }
6356 } else {
6357 conn = NULL;
6358 }
6359
6360 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6361 if (!cmd) {
6362 err = -ENOMEM;
6363 goto unlock;
6364 }
6365
Johan Hedberg69487372014-12-05 13:36:07 +02006366 cmd->cmd_complete = clock_info_cmd_complete;
6367
Johan Hedberg95868422014-06-28 17:54:07 +03006368 hci_req_init(&req, hdev);
6369
6370 memset(&hci_cp, 0, sizeof(hci_cp));
6371 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6372
6373 if (conn) {
6374 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006375 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006376
6377 hci_cp.handle = cpu_to_le16(conn->handle);
6378 hci_cp.which = 0x01; /* Piconet clock */
6379 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6380 }
6381
6382 err = hci_req_run(&req, get_clock_info_complete);
6383 if (err < 0)
6384 mgmt_pending_remove(cmd);
6385
6386unlock:
6387 hci_dev_unlock(hdev);
6388 return err;
6389}
6390
Johan Hedberg5a154e62014-12-19 22:26:02 +02006391static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6392{
6393 struct hci_conn *conn;
6394
6395 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6396 if (!conn)
6397 return false;
6398
6399 if (conn->dst_type != type)
6400 return false;
6401
6402 if (conn->state != BT_CONNECTED)
6403 return false;
6404
6405 return true;
6406}
6407
6408/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006409static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006410 u8 addr_type, u8 auto_connect)
6411{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006412 struct hci_conn_params *params;
6413
6414 params = hci_conn_params_add(hdev, addr, addr_type);
6415 if (!params)
6416 return -EIO;
6417
6418 if (params->auto_connect == auto_connect)
6419 return 0;
6420
6421 list_del_init(&params->action);
6422
6423 switch (auto_connect) {
6424 case HCI_AUTO_CONN_DISABLED:
6425 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006426 /* If auto connect is being disabled when we're trying to
6427 * connect to device, keep connecting.
6428 */
6429 if (params->explicit_connect)
6430 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006431 break;
6432 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006433 if (params->explicit_connect)
6434 list_add(&params->action, &hdev->pend_le_conns);
6435 else
6436 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006437 break;
6438 case HCI_AUTO_CONN_DIRECT:
6439 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006440 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006441 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006442 break;
6443 }
6444
6445 params->auto_connect = auto_connect;
6446
Marcel Holtmann181d6952020-05-06 09:57:47 +02006447 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6448 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006449
6450 return 0;
6451}
6452
Marcel Holtmann8afef092014-06-29 22:28:34 +02006453static void device_added(struct sock *sk, struct hci_dev *hdev,
6454 bdaddr_t *bdaddr, u8 type, u8 action)
6455{
6456 struct mgmt_ev_device_added ev;
6457
6458 bacpy(&ev.addr.bdaddr, bdaddr);
6459 ev.addr.type = type;
6460 ev.action = action;
6461
6462 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6463}
6464
Marcel Holtmann2faade52014-06-29 19:44:03 +02006465static int add_device(struct sock *sk, struct hci_dev *hdev,
6466 void *data, u16 len)
6467{
6468 struct mgmt_cp_add_device *cp = data;
6469 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006470 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006471 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006472 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006473
Marcel Holtmann181d6952020-05-06 09:57:47 +02006474 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006475
Johan Hedberg66593582014-07-09 12:59:14 +03006476 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006477 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006478 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6479 MGMT_STATUS_INVALID_PARAMS,
6480 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006481
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006482 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006483 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6484 MGMT_STATUS_INVALID_PARAMS,
6485 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006486
6487 hci_dev_lock(hdev);
6488
Johan Hedberg66593582014-07-09 12:59:14 +03006489 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006490 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006491 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006492 err = mgmt_cmd_complete(sk, hdev->id,
6493 MGMT_OP_ADD_DEVICE,
6494 MGMT_STATUS_INVALID_PARAMS,
6495 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006496 goto unlock;
6497 }
6498
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006499 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6500 &cp->addr.bdaddr,
6501 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006502 if (err)
6503 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006504
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006505 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006506
Johan Hedberg66593582014-07-09 12:59:14 +03006507 goto added;
6508 }
6509
Johan Hedberg85813a72015-10-21 18:02:59 +03006510 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006511
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006512 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006513 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006514 else if (cp->action == 0x01)
6515 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006516 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006517 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006518
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006519 /* Kernel internally uses conn_params with resolvable private
6520 * address, but Add Device allows only identity addresses.
6521 * Make sure it is enforced before calling
6522 * hci_conn_params_lookup.
6523 */
6524 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006525 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6526 MGMT_STATUS_INVALID_PARAMS,
6527 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006528 goto unlock;
6529 }
6530
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006531 /* If the connection parameters don't exist for this device,
6532 * they will be created and configured with defaults.
6533 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006534 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006535 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006536 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6537 MGMT_STATUS_FAILED, &cp->addr,
6538 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006539 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006540 } else {
6541 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6542 addr_type);
6543 if (params)
6544 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006545 }
6546
Johan Hedberg51d7a942015-11-11 08:11:18 +02006547 hci_update_background_scan(hdev);
6548
Johan Hedberg66593582014-07-09 12:59:14 +03006549added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006550 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006551 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6552 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006553
Johan Hedberg51d7a942015-11-11 08:11:18 +02006554 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6555 MGMT_STATUS_SUCCESS, &cp->addr,
6556 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006557
6558unlock:
6559 hci_dev_unlock(hdev);
6560 return err;
6561}
6562
Marcel Holtmann8afef092014-06-29 22:28:34 +02006563static void device_removed(struct sock *sk, struct hci_dev *hdev,
6564 bdaddr_t *bdaddr, u8 type)
6565{
6566 struct mgmt_ev_device_removed ev;
6567
6568 bacpy(&ev.addr.bdaddr, bdaddr);
6569 ev.addr.type = type;
6570
6571 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6572}
6573
Marcel Holtmann2faade52014-06-29 19:44:03 +02006574static int remove_device(struct sock *sk, struct hci_dev *hdev,
6575 void *data, u16 len)
6576{
6577 struct mgmt_cp_remove_device *cp = data;
6578 int err;
6579
Marcel Holtmann181d6952020-05-06 09:57:47 +02006580 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006581
6582 hci_dev_lock(hdev);
6583
6584 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006585 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006586 u8 addr_type;
6587
Johan Hedberg66593582014-07-09 12:59:14 +03006588 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006589 err = mgmt_cmd_complete(sk, hdev->id,
6590 MGMT_OP_REMOVE_DEVICE,
6591 MGMT_STATUS_INVALID_PARAMS,
6592 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006593 goto unlock;
6594 }
6595
Johan Hedberg66593582014-07-09 12:59:14 +03006596 if (cp->addr.type == BDADDR_BREDR) {
6597 err = hci_bdaddr_list_del(&hdev->whitelist,
6598 &cp->addr.bdaddr,
6599 cp->addr.type);
6600 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006601 err = mgmt_cmd_complete(sk, hdev->id,
6602 MGMT_OP_REMOVE_DEVICE,
6603 MGMT_STATUS_INVALID_PARAMS,
6604 &cp->addr,
6605 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006606 goto unlock;
6607 }
6608
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006609 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006610
Johan Hedberg66593582014-07-09 12:59:14 +03006611 device_removed(sk, hdev, &cp->addr.bdaddr,
6612 cp->addr.type);
6613 goto complete;
6614 }
6615
Johan Hedberg85813a72015-10-21 18:02:59 +03006616 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006617
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006618 /* Kernel internally uses conn_params with resolvable private
6619 * address, but Remove Device allows only identity addresses.
6620 * Make sure it is enforced before calling
6621 * hci_conn_params_lookup.
6622 */
6623 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006624 err = mgmt_cmd_complete(sk, hdev->id,
6625 MGMT_OP_REMOVE_DEVICE,
6626 MGMT_STATUS_INVALID_PARAMS,
6627 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006628 goto unlock;
6629 }
6630
Johan Hedbergc71593d2014-07-02 17:37:28 +03006631 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6632 addr_type);
6633 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006634 err = mgmt_cmd_complete(sk, hdev->id,
6635 MGMT_OP_REMOVE_DEVICE,
6636 MGMT_STATUS_INVALID_PARAMS,
6637 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006638 goto unlock;
6639 }
6640
Johan Hedberg679d2b62015-10-16 10:07:52 +03006641 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6642 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006643 err = mgmt_cmd_complete(sk, hdev->id,
6644 MGMT_OP_REMOVE_DEVICE,
6645 MGMT_STATUS_INVALID_PARAMS,
6646 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006647 goto unlock;
6648 }
6649
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006650 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006651 list_del(&params->list);
6652 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006653 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006654
6655 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006656 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006657 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006658 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006659
Marcel Holtmann2faade52014-06-29 19:44:03 +02006660 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006661 err = mgmt_cmd_complete(sk, hdev->id,
6662 MGMT_OP_REMOVE_DEVICE,
6663 MGMT_STATUS_INVALID_PARAMS,
6664 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006665 goto unlock;
6666 }
6667
Johan Hedberg66593582014-07-09 12:59:14 +03006668 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6669 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6670 list_del(&b->list);
6671 kfree(b);
6672 }
6673
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006674 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006675
Johan Hedberg19de0822014-07-06 13:06:51 +03006676 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6677 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6678 continue;
6679 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006680 if (p->explicit_connect) {
6681 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6682 continue;
6683 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006684 list_del(&p->action);
6685 list_del(&p->list);
6686 kfree(p);
6687 }
6688
Marcel Holtmann181d6952020-05-06 09:57:47 +02006689 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006690
Johan Hedberg51d7a942015-11-11 08:11:18 +02006691 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006692 }
6693
Johan Hedberg66593582014-07-09 12:59:14 +03006694complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006695 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6696 MGMT_STATUS_SUCCESS, &cp->addr,
6697 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006698unlock:
6699 hci_dev_unlock(hdev);
6700 return err;
6701}
6702
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006703static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6704 u16 len)
6705{
6706 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006707 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6708 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006709 u16 param_count, expected_len;
6710 int i;
6711
6712 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6714 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006715
6716 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006717 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006718 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6719 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006720 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6721 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006722 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006723
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006724 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006725 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006726 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6727 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006728 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6729 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006730 }
6731
Marcel Holtmann181d6952020-05-06 09:57:47 +02006732 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006733
6734 hci_dev_lock(hdev);
6735
6736 hci_conn_params_clear_disabled(hdev);
6737
6738 for (i = 0; i < param_count; i++) {
6739 struct mgmt_conn_param *param = &cp->params[i];
6740 struct hci_conn_params *hci_param;
6741 u16 min, max, latency, timeout;
6742 u8 addr_type;
6743
Marcel Holtmann181d6952020-05-06 09:57:47 +02006744 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6745 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006746
6747 if (param->addr.type == BDADDR_LE_PUBLIC) {
6748 addr_type = ADDR_LE_DEV_PUBLIC;
6749 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6750 addr_type = ADDR_LE_DEV_RANDOM;
6751 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006752 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006753 continue;
6754 }
6755
6756 min = le16_to_cpu(param->min_interval);
6757 max = le16_to_cpu(param->max_interval);
6758 latency = le16_to_cpu(param->latency);
6759 timeout = le16_to_cpu(param->timeout);
6760
Marcel Holtmann181d6952020-05-06 09:57:47 +02006761 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6762 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006763
6764 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006765 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006766 continue;
6767 }
6768
6769 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6770 addr_type);
6771 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006772 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006773 continue;
6774 }
6775
6776 hci_param->conn_min_interval = min;
6777 hci_param->conn_max_interval = max;
6778 hci_param->conn_latency = latency;
6779 hci_param->supervision_timeout = timeout;
6780 }
6781
6782 hci_dev_unlock(hdev);
6783
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006784 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6785 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006786}
6787
Marcel Holtmanndbece372014-07-04 18:11:55 +02006788static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6789 void *data, u16 len)
6790{
6791 struct mgmt_cp_set_external_config *cp = data;
6792 bool changed;
6793 int err;
6794
Marcel Holtmann181d6952020-05-06 09:57:47 +02006795 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006796
6797 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6799 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006800
6801 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006802 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6803 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006804
6805 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006806 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6807 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006808
6809 hci_dev_lock(hdev);
6810
6811 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006812 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006813 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006814 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006815
6816 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6817 if (err < 0)
6818 goto unlock;
6819
6820 if (!changed)
6821 goto unlock;
6822
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006823 err = new_options(hdev, sk);
6824
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006825 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006826 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006827
Marcel Holtmann516018a2015-03-13 02:11:04 -07006828 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006829 hci_dev_set_flag(hdev, HCI_CONFIG);
6830 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006831
6832 queue_work(hdev->req_workqueue, &hdev->power_on);
6833 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006834 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006835 mgmt_index_added(hdev);
6836 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006837 }
6838
6839unlock:
6840 hci_dev_unlock(hdev);
6841 return err;
6842}
6843
Marcel Holtmann9713c172014-07-06 12:11:15 +02006844static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6845 void *data, u16 len)
6846{
6847 struct mgmt_cp_set_public_address *cp = data;
6848 bool changed;
6849 int err;
6850
Marcel Holtmann181d6952020-05-06 09:57:47 +02006851 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006852
6853 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006854 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6855 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006856
6857 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006858 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6859 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006860
6861 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006862 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6863 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006864
6865 hci_dev_lock(hdev);
6866
6867 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6868 bacpy(&hdev->public_addr, &cp->bdaddr);
6869
6870 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6871 if (err < 0)
6872 goto unlock;
6873
6874 if (!changed)
6875 goto unlock;
6876
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006877 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006878 err = new_options(hdev, sk);
6879
6880 if (is_configured(hdev)) {
6881 mgmt_index_removed(hdev);
6882
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006883 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006884
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006885 hci_dev_set_flag(hdev, HCI_CONFIG);
6886 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006887
6888 queue_work(hdev->req_workqueue, &hdev->power_on);
6889 }
6890
6891unlock:
6892 hci_dev_unlock(hdev);
6893 return err;
6894}
6895
Johan Hedberg40f66c02015-04-07 21:52:22 +03006896static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6897 u16 opcode, struct sk_buff *skb)
6898{
6899 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6900 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6901 u8 *h192, *r192, *h256, *r256;
6902 struct mgmt_pending_cmd *cmd;
6903 u16 eir_len;
6904 int err;
6905
Marcel Holtmann181d6952020-05-06 09:57:47 +02006906 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006907
6908 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6909 if (!cmd)
6910 return;
6911
6912 mgmt_cp = cmd->param;
6913
6914 if (status) {
6915 status = mgmt_status(status);
6916 eir_len = 0;
6917
6918 h192 = NULL;
6919 r192 = NULL;
6920 h256 = NULL;
6921 r256 = NULL;
6922 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6923 struct hci_rp_read_local_oob_data *rp;
6924
6925 if (skb->len != sizeof(*rp)) {
6926 status = MGMT_STATUS_FAILED;
6927 eir_len = 0;
6928 } else {
6929 status = MGMT_STATUS_SUCCESS;
6930 rp = (void *)skb->data;
6931
6932 eir_len = 5 + 18 + 18;
6933 h192 = rp->hash;
6934 r192 = rp->rand;
6935 h256 = NULL;
6936 r256 = NULL;
6937 }
6938 } else {
6939 struct hci_rp_read_local_oob_ext_data *rp;
6940
6941 if (skb->len != sizeof(*rp)) {
6942 status = MGMT_STATUS_FAILED;
6943 eir_len = 0;
6944 } else {
6945 status = MGMT_STATUS_SUCCESS;
6946 rp = (void *)skb->data;
6947
6948 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6949 eir_len = 5 + 18 + 18;
6950 h192 = NULL;
6951 r192 = NULL;
6952 } else {
6953 eir_len = 5 + 18 + 18 + 18 + 18;
6954 h192 = rp->hash192;
6955 r192 = rp->rand192;
6956 }
6957
6958 h256 = rp->hash256;
6959 r256 = rp->rand256;
6960 }
6961 }
6962
6963 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6964 if (!mgmt_rp)
6965 goto done;
6966
6967 if (status)
6968 goto send_rsp;
6969
6970 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6971 hdev->dev_class, 3);
6972
6973 if (h192 && r192) {
6974 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6975 EIR_SSP_HASH_C192, h192, 16);
6976 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6977 EIR_SSP_RAND_R192, r192, 16);
6978 }
6979
6980 if (h256 && r256) {
6981 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6982 EIR_SSP_HASH_C256, h256, 16);
6983 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6984 EIR_SSP_RAND_R256, r256, 16);
6985 }
6986
6987send_rsp:
6988 mgmt_rp->type = mgmt_cp->type;
6989 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6990
6991 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6992 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6993 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6994 if (err < 0 || status)
6995 goto done;
6996
6997 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6998
6999 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7000 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7001 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7002done:
7003 kfree(mgmt_rp);
7004 mgmt_pending_remove(cmd);
7005}
7006
7007static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7008 struct mgmt_cp_read_local_oob_ext_data *cp)
7009{
7010 struct mgmt_pending_cmd *cmd;
7011 struct hci_request req;
7012 int err;
7013
7014 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7015 cp, sizeof(*cp));
7016 if (!cmd)
7017 return -ENOMEM;
7018
7019 hci_req_init(&req, hdev);
7020
7021 if (bredr_sc_enabled(hdev))
7022 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7023 else
7024 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7025
7026 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7027 if (err < 0) {
7028 mgmt_pending_remove(cmd);
7029 return err;
7030 }
7031
7032 return 0;
7033}
7034
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007035static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7036 void *data, u16 data_len)
7037{
7038 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7039 struct mgmt_rp_read_local_oob_ext_data *rp;
7040 size_t rp_len;
7041 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007042 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007043 int err;
7044
Marcel Holtmann181d6952020-05-06 09:57:47 +02007045 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007046
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007047 if (hdev_is_powered(hdev)) {
7048 switch (cp->type) {
7049 case BIT(BDADDR_BREDR):
7050 status = mgmt_bredr_support(hdev);
7051 if (status)
7052 eir_len = 0;
7053 else
7054 eir_len = 5;
7055 break;
7056 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7057 status = mgmt_le_support(hdev);
7058 if (status)
7059 eir_len = 0;
7060 else
7061 eir_len = 9 + 3 + 18 + 18 + 3;
7062 break;
7063 default:
7064 status = MGMT_STATUS_INVALID_PARAMS;
7065 eir_len = 0;
7066 break;
7067 }
7068 } else {
7069 status = MGMT_STATUS_NOT_POWERED;
7070 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007071 }
7072
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007073 rp_len = sizeof(*rp) + eir_len;
7074 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007075 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007076 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007077
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007078 if (status)
7079 goto complete;
7080
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007081 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007082
7083 eir_len = 0;
7084 switch (cp->type) {
7085 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007086 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7087 err = read_local_ssp_oob_req(hdev, sk, cp);
7088 hci_dev_unlock(hdev);
7089 if (!err)
7090 goto done;
7091
7092 status = MGMT_STATUS_FAILED;
7093 goto complete;
7094 } else {
7095 eir_len = eir_append_data(rp->eir, eir_len,
7096 EIR_CLASS_OF_DEV,
7097 hdev->dev_class, 3);
7098 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007099 break;
7100 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007101 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7102 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007103 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007104 status = MGMT_STATUS_FAILED;
7105 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007106 }
7107
Marcel Holtmanne2135682015-04-02 12:00:58 -07007108 /* This should return the active RPA, but since the RPA
7109 * is only programmed on demand, it is really hard to fill
7110 * this in at the moment. For now disallow retrieving
7111 * local out-of-band data when privacy is in use.
7112 *
7113 * Returning the identity address will not help here since
7114 * pairing happens before the identity resolving key is
7115 * known and thus the connection establishment happens
7116 * based on the RPA and not the identity address.
7117 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007118 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007119 hci_dev_unlock(hdev);
7120 status = MGMT_STATUS_REJECTED;
7121 goto complete;
7122 }
7123
7124 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7125 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7126 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7127 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007128 memcpy(addr, &hdev->static_addr, 6);
7129 addr[6] = 0x01;
7130 } else {
7131 memcpy(addr, &hdev->bdaddr, 6);
7132 addr[6] = 0x00;
7133 }
7134
7135 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7136 addr, sizeof(addr));
7137
7138 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7139 role = 0x02;
7140 else
7141 role = 0x01;
7142
7143 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7144 &role, sizeof(role));
7145
Marcel Holtmann5082a592015-03-16 12:39:00 -07007146 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7147 eir_len = eir_append_data(rp->eir, eir_len,
7148 EIR_LE_SC_CONFIRM,
7149 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007150
Marcel Holtmann5082a592015-03-16 12:39:00 -07007151 eir_len = eir_append_data(rp->eir, eir_len,
7152 EIR_LE_SC_RANDOM,
7153 rand, sizeof(rand));
7154 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007155
Johan Hedbergf2252572015-11-18 12:49:20 +02007156 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007157
7158 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7159 flags |= LE_AD_NO_BREDR;
7160
7161 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7162 &flags, sizeof(flags));
7163 break;
7164 }
7165
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007166 hci_dev_unlock(hdev);
7167
Marcel Holtmann72000df2015-03-16 16:11:21 -07007168 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7169
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007170 status = MGMT_STATUS_SUCCESS;
7171
7172complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007173 rp->type = cp->type;
7174 rp->eir_len = cpu_to_le16(eir_len);
7175
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007176 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007177 status, rp, sizeof(*rp) + eir_len);
7178 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007179 goto done;
7180
7181 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7182 rp, sizeof(*rp) + eir_len,
7183 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007184
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007185done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007186 kfree(rp);
7187
7188 return err;
7189}
7190
Arman Uguray089fa8c2015-03-25 18:53:45 -07007191static u32 get_supported_adv_flags(struct hci_dev *hdev)
7192{
7193 u32 flags = 0;
7194
7195 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7196 flags |= MGMT_ADV_FLAG_DISCOV;
7197 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7198 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007199 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007200 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007201
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307202 /* In extended adv TX_POWER returned from Set Adv Param
7203 * will be always valid.
7204 */
7205 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7206 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007207 flags |= MGMT_ADV_FLAG_TX_POWER;
7208
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307209 if (ext_adv_capable(hdev)) {
7210 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007211 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7212 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307213
7214 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7215 flags |= MGMT_ADV_FLAG_SEC_2M;
7216
7217 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7218 flags |= MGMT_ADV_FLAG_SEC_CODED;
7219 }
7220
Arman Uguray089fa8c2015-03-25 18:53:45 -07007221 return flags;
7222}
7223
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007224static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7225 void *data, u16 data_len)
7226{
7227 struct mgmt_rp_read_adv_features *rp;
7228 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007229 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007230 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007231 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007232 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007233
Marcel Holtmann181d6952020-05-06 09:57:47 +02007234 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007235
Arman Uguray089fa8c2015-03-25 18:53:45 -07007236 if (!lmp_le_capable(hdev))
7237 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7238 MGMT_STATUS_REJECTED);
7239
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307240 /* Enabling the experimental LL Privay support disables support for
7241 * advertising.
7242 */
7243 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7244 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7245 MGMT_STATUS_NOT_SUPPORTED);
7246
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007247 hci_dev_lock(hdev);
7248
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007249 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007250 rp = kmalloc(rp_len, GFP_ATOMIC);
7251 if (!rp) {
7252 hci_dev_unlock(hdev);
7253 return -ENOMEM;
7254 }
7255
Arman Uguray089fa8c2015-03-25 18:53:45 -07007256 supported_flags = get_supported_adv_flags(hdev);
7257
7258 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007259 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7260 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007261 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007262 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007263
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007264 instance = rp->instance;
7265 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7266 *instance = adv_instance->instance;
7267 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007268 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007269
7270 hci_dev_unlock(hdev);
7271
7272 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7273 MGMT_STATUS_SUCCESS, rp, rp_len);
7274
7275 kfree(rp);
7276
7277 return err;
7278}
7279
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007280static u8 calculate_name_len(struct hci_dev *hdev)
7281{
7282 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7283
7284 return append_local_name(hdev, buf, 0);
7285}
7286
7287static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7288 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007289{
Arman Uguray4117ed72015-03-23 15:57:14 -07007290 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007291
Marcel Holtmann31a32482015-11-19 16:16:42 +01007292 if (is_adv_data) {
7293 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7294 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007295 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007296 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007297
Szymon Janc2bb368702016-09-18 12:50:05 +02007298 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007299 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007300 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007301 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007302 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007303
Szymon Janc2bb368702016-09-18 12:50:05 +02007304 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007305 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007306 }
7307
Szymon Janc2bb368702016-09-18 12:50:05 +02007308 return max_len;
7309}
7310
7311static bool flags_managed(u32 adv_flags)
7312{
7313 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7314 MGMT_ADV_FLAG_LIMITED_DISCOV |
7315 MGMT_ADV_FLAG_MANAGED_FLAGS);
7316}
7317
7318static bool tx_power_managed(u32 adv_flags)
7319{
7320 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7321}
7322
7323static bool name_managed(u32 adv_flags)
7324{
7325 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7326}
7327
7328static bool appearance_managed(u32 adv_flags)
7329{
7330 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7331}
7332
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007333static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7334 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007335{
7336 int i, cur_len;
7337 u8 max_len;
7338
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007339 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007340
Arman Uguray4117ed72015-03-23 15:57:14 -07007341 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007342 return false;
7343
Arman Uguray4117ed72015-03-23 15:57:14 -07007344 /* Make sure that the data is correctly formatted. */
7345 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7346 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007347
Szymon Janc9c9db782016-09-18 12:50:06 +02007348 if (data[i + 1] == EIR_FLAGS &&
7349 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007350 return false;
7351
Szymon Janc2bb368702016-09-18 12:50:05 +02007352 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7353 return false;
7354
7355 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7356 return false;
7357
7358 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7359 return false;
7360
7361 if (data[i + 1] == EIR_APPEARANCE &&
7362 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007363 return false;
7364
Arman Uguray24b4f382015-03-23 15:57:12 -07007365 /* If the current field length would exceed the total data
7366 * length, then it's invalid.
7367 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007368 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007369 return false;
7370 }
7371
7372 return true;
7373}
7374
Arman Uguray24b4f382015-03-23 15:57:12 -07007375static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7376 u16 opcode)
7377{
7378 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007379 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007380 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007381 struct adv_info *adv_instance, *n;
7382 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007383
Marcel Holtmann181d6952020-05-06 09:57:47 +02007384 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007385
7386 hci_dev_lock(hdev);
7387
7388 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7389
Florian Grandelfffd38b2015-06-18 03:16:47 +02007390 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7391 if (!adv_instance->pending)
7392 continue;
7393
7394 if (!status) {
7395 adv_instance->pending = false;
7396 continue;
7397 }
7398
7399 instance = adv_instance->instance;
7400
7401 if (hdev->cur_adv_instance == instance)
7402 cancel_adv_timeout(hdev);
7403
7404 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007405 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007406 }
7407
7408 if (!cmd)
7409 goto unlock;
7410
Florian Grandelfffd38b2015-06-18 03:16:47 +02007411 cp = cmd->param;
7412 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007413
7414 if (status)
7415 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7416 mgmt_status(status));
7417 else
7418 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7419 mgmt_status(status), &rp, sizeof(rp));
7420
7421 mgmt_pending_remove(cmd);
7422
7423unlock:
7424 hci_dev_unlock(hdev);
7425}
7426
7427static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7428 void *data, u16 data_len)
7429{
7430 struct mgmt_cp_add_advertising *cp = data;
7431 struct mgmt_rp_add_advertising rp;
7432 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307433 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007434 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007435 u16 timeout, duration;
7436 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7437 u8 schedule_instance = 0;
7438 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007439 int err;
7440 struct mgmt_pending_cmd *cmd;
7441 struct hci_request req;
7442
Marcel Holtmann181d6952020-05-06 09:57:47 +02007443 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007444
7445 status = mgmt_le_support(hdev);
7446 if (status)
7447 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7448 status);
7449
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307450 /* Enabling the experimental LL Privay support disables support for
7451 * advertising.
7452 */
7453 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7454 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7455 MGMT_STATUS_NOT_SUPPORTED);
7456
Daniel Winkler87597482020-08-25 16:31:50 -07007457 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007458 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7459 MGMT_STATUS_INVALID_PARAMS);
7460
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007461 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7462 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7463 MGMT_STATUS_INVALID_PARAMS);
7464
Arman Uguray24b4f382015-03-23 15:57:12 -07007465 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007466 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007467 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007468
Florian Grandelfffd38b2015-06-18 03:16:47 +02007469 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307470 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007471 */
7472 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307473 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7474 if (flags & ~supported_flags ||
7475 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007476 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7477 MGMT_STATUS_INVALID_PARAMS);
7478
7479 hci_dev_lock(hdev);
7480
Arman Uguray912098a2015-03-23 15:57:15 -07007481 if (timeout && !hdev_is_powered(hdev)) {
7482 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7483 MGMT_STATUS_REJECTED);
7484 goto unlock;
7485 }
7486
Arman Uguray24b4f382015-03-23 15:57:12 -07007487 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007488 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007489 pending_find(MGMT_OP_SET_LE, hdev)) {
7490 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7491 MGMT_STATUS_BUSY);
7492 goto unlock;
7493 }
7494
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007495 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7496 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007497 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007498 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7499 MGMT_STATUS_INVALID_PARAMS);
7500 goto unlock;
7501 }
7502
Florian Grandelfffd38b2015-06-18 03:16:47 +02007503 err = hci_add_adv_instance(hdev, cp->instance, flags,
7504 cp->adv_data_len, cp->data,
7505 cp->scan_rsp_len,
7506 cp->data + cp->adv_data_len,
7507 timeout, duration);
7508 if (err < 0) {
7509 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7510 MGMT_STATUS_FAILED);
7511 goto unlock;
7512 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007513
Florian Grandelfffd38b2015-06-18 03:16:47 +02007514 /* Only trigger an advertising added event if a new instance was
7515 * actually added.
7516 */
7517 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007518 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007519
Florian Grandelfffd38b2015-06-18 03:16:47 +02007520 if (hdev->cur_adv_instance == cp->instance) {
7521 /* If the currently advertised instance is being changed then
7522 * cancel the current advertising and schedule the next
7523 * instance. If there is only one instance then the overridden
7524 * advertising data will be visible right away.
7525 */
7526 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007527
Florian Grandelfffd38b2015-06-18 03:16:47 +02007528 next_instance = hci_get_next_instance(hdev, cp->instance);
7529 if (next_instance)
7530 schedule_instance = next_instance->instance;
7531 } else if (!hdev->adv_instance_timeout) {
7532 /* Immediately advertise the new instance if no other
7533 * instance is currently being advertised.
7534 */
7535 schedule_instance = cp->instance;
7536 }
Arman Uguray912098a2015-03-23 15:57:15 -07007537
Florian Grandelfffd38b2015-06-18 03:16:47 +02007538 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7539 * there is no instance to be advertised then we have no HCI
7540 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007541 */
7542 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007543 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7544 !schedule_instance) {
7545 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007546 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7547 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7548 goto unlock;
7549 }
7550
7551 /* We're good to go, update advertising data, parameters, and start
7552 * advertising.
7553 */
7554 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7555 data_len);
7556 if (!cmd) {
7557 err = -ENOMEM;
7558 goto unlock;
7559 }
7560
7561 hci_req_init(&req, hdev);
7562
Johan Hedbergf2252572015-11-18 12:49:20 +02007563 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007564
Florian Grandelfffd38b2015-06-18 03:16:47 +02007565 if (!err)
7566 err = hci_req_run(&req, add_advertising_complete);
7567
Joseph Hwang72da7b22020-03-10 09:31:50 -07007568 if (err < 0) {
7569 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7570 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007571 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007572 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007573
7574unlock:
7575 hci_dev_unlock(hdev);
7576
7577 return err;
7578}
7579
Arman Ugurayda9293352015-03-23 15:57:13 -07007580static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7581 u16 opcode)
7582{
7583 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007584 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007585 struct mgmt_rp_remove_advertising rp;
7586
Marcel Holtmann181d6952020-05-06 09:57:47 +02007587 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007588
7589 hci_dev_lock(hdev);
7590
7591 /* A failure status here only means that we failed to disable
7592 * advertising. Otherwise, the advertising instance has been removed,
7593 * so report success.
7594 */
7595 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7596 if (!cmd)
7597 goto unlock;
7598
Florian Grandel01948332015-06-18 03:16:48 +02007599 cp = cmd->param;
7600 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007601
7602 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7603 &rp, sizeof(rp));
7604 mgmt_pending_remove(cmd);
7605
7606unlock:
7607 hci_dev_unlock(hdev);
7608}
7609
7610static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7611 void *data, u16 data_len)
7612{
7613 struct mgmt_cp_remove_advertising *cp = data;
7614 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007615 struct mgmt_pending_cmd *cmd;
7616 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007617 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007618
Marcel Holtmann181d6952020-05-06 09:57:47 +02007619 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007620
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307621 /* Enabling the experimental LL Privay support disables support for
7622 * advertising.
7623 */
7624 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7625 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7626 MGMT_STATUS_NOT_SUPPORTED);
7627
Arman Ugurayda9293352015-03-23 15:57:13 -07007628 hci_dev_lock(hdev);
7629
Johan Hedberg952497b2015-06-18 21:05:31 +03007630 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007631 err = mgmt_cmd_status(sk, hdev->id,
7632 MGMT_OP_REMOVE_ADVERTISING,
7633 MGMT_STATUS_INVALID_PARAMS);
7634 goto unlock;
7635 }
7636
Arman Ugurayda9293352015-03-23 15:57:13 -07007637 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7638 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7639 pending_find(MGMT_OP_SET_LE, hdev)) {
7640 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7641 MGMT_STATUS_BUSY);
7642 goto unlock;
7643 }
7644
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007645 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007646 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7647 MGMT_STATUS_INVALID_PARAMS);
7648 goto unlock;
7649 }
7650
Florian Grandel01948332015-06-18 03:16:48 +02007651 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007652
Daniel Winkler37adf702020-07-14 14:16:00 -07007653 /* If we use extended advertising, instance is disabled and removed */
7654 if (ext_adv_capable(hdev)) {
7655 __hci_req_disable_ext_adv_instance(&req, cp->instance);
7656 __hci_req_remove_ext_adv_instance(&req, cp->instance);
7657 }
7658
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007659 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007660
Florian Grandel01948332015-06-18 03:16:48 +02007661 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007662 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007663
Florian Grandel01948332015-06-18 03:16:48 +02007664 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7665 * flag is set or the device isn't powered then we have no HCI
7666 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007667 */
Florian Grandel01948332015-06-18 03:16:48 +02007668 if (skb_queue_empty(&req.cmd_q) ||
7669 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007670 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307671 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007672 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007673 err = mgmt_cmd_complete(sk, hdev->id,
7674 MGMT_OP_REMOVE_ADVERTISING,
7675 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7676 goto unlock;
7677 }
7678
7679 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7680 data_len);
7681 if (!cmd) {
7682 err = -ENOMEM;
7683 goto unlock;
7684 }
7685
Arman Ugurayda9293352015-03-23 15:57:13 -07007686 err = hci_req_run(&req, remove_advertising_complete);
7687 if (err < 0)
7688 mgmt_pending_remove(cmd);
7689
7690unlock:
7691 hci_dev_unlock(hdev);
7692
7693 return err;
7694}
7695
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007696static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7697 void *data, u16 data_len)
7698{
7699 struct mgmt_cp_get_adv_size_info *cp = data;
7700 struct mgmt_rp_get_adv_size_info rp;
7701 u32 flags, supported_flags;
7702 int err;
7703
Marcel Holtmann181d6952020-05-06 09:57:47 +02007704 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007705
7706 if (!lmp_le_capable(hdev))
7707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7708 MGMT_STATUS_REJECTED);
7709
Daniel Winkler87597482020-08-25 16:31:50 -07007710 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007711 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7712 MGMT_STATUS_INVALID_PARAMS);
7713
7714 flags = __le32_to_cpu(cp->flags);
7715
7716 /* The current implementation only supports a subset of the specified
7717 * flags.
7718 */
7719 supported_flags = get_supported_adv_flags(hdev);
7720 if (flags & ~supported_flags)
7721 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7722 MGMT_STATUS_INVALID_PARAMS);
7723
7724 rp.instance = cp->instance;
7725 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007726 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7727 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007728
7729 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7730 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7731
7732 return err;
7733}
7734
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007735static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007736 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007737 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007738 HCI_MGMT_NO_HDEV |
7739 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007740 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007741 HCI_MGMT_NO_HDEV |
7742 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007743 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007744 HCI_MGMT_NO_HDEV |
7745 HCI_MGMT_UNTRUSTED },
7746 { read_controller_info, MGMT_READ_INFO_SIZE,
7747 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007748 { set_powered, MGMT_SETTING_SIZE },
7749 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7750 { set_connectable, MGMT_SETTING_SIZE },
7751 { set_fast_connectable, MGMT_SETTING_SIZE },
7752 { set_bondable, MGMT_SETTING_SIZE },
7753 { set_link_security, MGMT_SETTING_SIZE },
7754 { set_ssp, MGMT_SETTING_SIZE },
7755 { set_hs, MGMT_SETTING_SIZE },
7756 { set_le, MGMT_SETTING_SIZE },
7757 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7758 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7759 { add_uuid, MGMT_ADD_UUID_SIZE },
7760 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007761 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7762 HCI_MGMT_VAR_LEN },
7763 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7764 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007765 { disconnect, MGMT_DISCONNECT_SIZE },
7766 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7767 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7768 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7769 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7770 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7771 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7772 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7773 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7774 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7775 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7776 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007777 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7778 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7779 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007780 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7781 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7782 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7783 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7784 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7785 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7786 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7787 { set_advertising, MGMT_SETTING_SIZE },
7788 { set_bredr, MGMT_SETTING_SIZE },
7789 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7790 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7791 { set_secure_conn, MGMT_SETTING_SIZE },
7792 { set_debug_keys, MGMT_SETTING_SIZE },
7793 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007794 { load_irks, MGMT_LOAD_IRKS_SIZE,
7795 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007796 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7797 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7798 { add_device, MGMT_ADD_DEVICE_SIZE },
7799 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007800 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7801 HCI_MGMT_VAR_LEN },
7802 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007803 HCI_MGMT_NO_HDEV |
7804 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007805 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007806 HCI_MGMT_UNCONFIGURED |
7807 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007808 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7809 HCI_MGMT_UNCONFIGURED },
7810 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7811 HCI_MGMT_UNCONFIGURED },
7812 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7813 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007814 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007815 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007816 HCI_MGMT_NO_HDEV |
7817 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007818 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007819 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7820 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007821 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007822 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007823 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007824 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7825 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007826 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307827 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307828 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007829 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7830 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007831 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007832 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7833 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007834 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7835 HCI_MGMT_UNTRUSTED |
7836 HCI_MGMT_HDEV_OPTIONAL },
7837 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7838 HCI_MGMT_VAR_LEN |
7839 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007840 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7841 HCI_MGMT_UNTRUSTED },
7842 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7843 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007844 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7845 HCI_MGMT_UNTRUSTED },
7846 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7847 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007848 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7849 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007850 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02007851 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
7852 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02007853 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007854};
7855
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007856void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007857{
Marcel Holtmannced85542015-03-14 19:27:56 -07007858 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007859
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007860 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7861 return;
7862
Marcel Holtmannf9207332015-03-14 19:27:55 -07007863 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007864 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007865 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7866 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7867 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007868 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007869 } else {
7870 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7871 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007872 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007873 }
7874 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007875 case HCI_AMP:
7876 ev.type = 0x02;
7877 break;
7878 default:
7879 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007880 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007881
7882 ev.bus = hdev->bus;
7883
7884 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7885 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007886}
7887
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007888void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007889{
Marcel Holtmannced85542015-03-14 19:27:56 -07007890 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007891 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007892
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007893 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7894 return;
7895
Marcel Holtmannf9207332015-03-14 19:27:55 -07007896 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007897 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007898 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007899
Marcel Holtmannf9207332015-03-14 19:27:55 -07007900 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7901 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7902 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007903 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007904 } else {
7905 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7906 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007907 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007908 }
7909 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007910 case HCI_AMP:
7911 ev.type = 0x02;
7912 break;
7913 default:
7914 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007915 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007916
7917 ev.bus = hdev->bus;
7918
7919 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7920 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007921}
7922
Andre Guedes6046dc32014-02-26 20:21:51 -03007923/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007924static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007925{
7926 struct hci_conn_params *p;
7927
7928 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007929 /* Needed for AUTO_OFF case where might not "really"
7930 * have been powered off.
7931 */
7932 list_del_init(&p->action);
7933
7934 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007935 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007936 case HCI_AUTO_CONN_ALWAYS:
7937 list_add(&p->action, &hdev->pend_le_conns);
7938 break;
7939 case HCI_AUTO_CONN_REPORT:
7940 list_add(&p->action, &hdev->pend_le_reports);
7941 break;
7942 default:
7943 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007944 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007945 }
7946}
7947
Johan Hedberg2ff13892015-11-25 16:15:44 +02007948void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007949{
7950 struct cmd_lookup match = { NULL, hdev };
7951
Marcel Holtmann181d6952020-05-06 09:57:47 +02007952 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007953
Johan Hedberg2ff13892015-11-25 16:15:44 +02007954 hci_dev_lock(hdev);
7955
7956 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007957 restart_le_actions(hdev);
7958 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007959 }
7960
Johan Hedberg229ab392013-03-15 17:06:53 -05007961 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7962
7963 new_settings(hdev, match.sk);
7964
Johan Hedberg229ab392013-03-15 17:06:53 -05007965 if (match.sk)
7966 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007967
7968 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007969}
7970
Johan Hedberg2ff13892015-11-25 16:15:44 +02007971void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007972{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007973 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007974 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007975
Johan Hedberg229ab392013-03-15 17:06:53 -05007976 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007977
7978 /* If the power off is because of hdev unregistration let
7979 * use the appropriate INVALID_INDEX status. Otherwise use
7980 * NOT_POWERED. We cover both scenarios here since later in
7981 * mgmt_index_removed() any hci_conn callbacks will have already
7982 * been triggered, potentially causing misleading DISCONNECTED
7983 * status responses.
7984 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007985 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007986 status = MGMT_STATUS_INVALID_INDEX;
7987 else
7988 status = MGMT_STATUS_NOT_POWERED;
7989
7990 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007991
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007992 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007993 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7994 zero_cod, sizeof(zero_cod),
7995 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007996 ext_info_changed(hdev, NULL);
7997 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007998
Johan Hedberg2ff13892015-11-25 16:15:44 +02007999 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008000
8001 if (match.sk)
8002 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008003}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008004
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008005void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008006{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008007 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008008 u8 status;
8009
Johan Hedberg333ae952015-03-17 13:48:47 +02008010 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008011 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008012 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008013
8014 if (err == -ERFKILL)
8015 status = MGMT_STATUS_RFKILLED;
8016 else
8017 status = MGMT_STATUS_FAILED;
8018
Johan Hedberga69e8372015-03-06 21:08:53 +02008019 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008020
8021 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008022}
8023
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008024void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8025 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008026{
Johan Hedberg86742e12011-11-07 23:13:38 +02008027 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008028
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008029 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008030
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008031 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008032 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008033 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008034 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008035 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008036 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008037
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008038 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008039}
Johan Hedbergf7520542011-01-20 12:34:39 +02008040
Johan Hedbergd7b25452014-05-23 13:19:53 +03008041static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8042{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008043 switch (ltk->type) {
8044 case SMP_LTK:
8045 case SMP_LTK_SLAVE:
8046 if (ltk->authenticated)
8047 return MGMT_LTK_AUTHENTICATED;
8048 return MGMT_LTK_UNAUTHENTICATED;
8049 case SMP_LTK_P256:
8050 if (ltk->authenticated)
8051 return MGMT_LTK_P256_AUTH;
8052 return MGMT_LTK_P256_UNAUTH;
8053 case SMP_LTK_P256_DEBUG:
8054 return MGMT_LTK_P256_DEBUG;
8055 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008056
8057 return MGMT_LTK_UNAUTHENTICATED;
8058}
8059
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008060void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008061{
8062 struct mgmt_ev_new_long_term_key ev;
8063
8064 memset(&ev, 0, sizeof(ev));
8065
Marcel Holtmann5192d302014-02-19 17:11:58 -08008066 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008067 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008068 * to store long term keys. Their addresses will change the
8069 * next time around.
8070 *
8071 * Only when a remote device provides an identity address
8072 * make sure the long term key is stored. If the remote
8073 * identity is known, the long term keys are internally
8074 * mapped to the identity address. So allow static random
8075 * and public addresses here.
8076 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008077 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8078 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8079 ev.store_hint = 0x00;
8080 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008081 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008082
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008083 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008084 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008085 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008086 ev.key.enc_size = key->enc_size;
8087 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008088 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008089
Johan Hedberg2ceba532014-06-16 19:25:16 +03008090 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008091 ev.key.master = 1;
8092
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008093 /* Make sure we copy only the significant bytes based on the
8094 * encryption key size, and set the rest of the value to zeroes.
8095 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008096 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008097 memset(ev.key.val + key->enc_size, 0,
8098 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008099
Marcel Holtmann083368f2013-10-15 14:26:29 -07008100 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008101}
8102
Johan Hedbergcad20c22015-10-12 13:36:19 +02008103void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008104{
8105 struct mgmt_ev_new_irk ev;
8106
8107 memset(&ev, 0, sizeof(ev));
8108
Johan Hedbergcad20c22015-10-12 13:36:19 +02008109 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008110
Johan Hedberg95fbac82014-02-19 15:18:31 +02008111 bacpy(&ev.rpa, &irk->rpa);
8112 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8113 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8114 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8115
8116 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8117}
8118
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008119void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8120 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008121{
8122 struct mgmt_ev_new_csrk ev;
8123
8124 memset(&ev, 0, sizeof(ev));
8125
8126 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008127 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008128 * to store signature resolving keys. Their addresses will change
8129 * the next time around.
8130 *
8131 * Only when a remote device provides an identity address
8132 * make sure the signature resolving key is stored. So allow
8133 * static random and public addresses here.
8134 */
8135 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8136 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8137 ev.store_hint = 0x00;
8138 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008139 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008140
8141 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8142 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008143 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008144 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8145
8146 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8147}
8148
Andre Guedesffb5a8272014-07-01 18:10:11 -03008149void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008150 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8151 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008152{
8153 struct mgmt_ev_new_conn_param ev;
8154
Johan Hedbergc103aea2014-07-02 17:37:34 +03008155 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8156 return;
8157
Andre Guedesffb5a8272014-07-01 18:10:11 -03008158 memset(&ev, 0, sizeof(ev));
8159 bacpy(&ev.addr.bdaddr, bdaddr);
8160 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008161 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008162 ev.min_interval = cpu_to_le16(min_interval);
8163 ev.max_interval = cpu_to_le16(max_interval);
8164 ev.latency = cpu_to_le16(latency);
8165 ev.timeout = cpu_to_le16(timeout);
8166
8167 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8168}
8169
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008170void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
8171 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008172{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008173 char buf[512];
8174 struct mgmt_ev_device_connected *ev = (void *) buf;
8175 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008176
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008177 bacpy(&ev->addr.bdaddr, &conn->dst);
8178 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008179
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008180 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008181
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008182 /* We must ensure that the EIR Data fields are ordered and
8183 * unique. Keep it simple for now and avoid the problem by not
8184 * adding any BR/EDR data to the LE adv.
8185 */
8186 if (conn->le_adv_data_len > 0) {
8187 memcpy(&ev->eir[eir_len],
8188 conn->le_adv_data, conn->le_adv_data_len);
8189 eir_len = conn->le_adv_data_len;
8190 } else {
8191 if (name_len > 0)
8192 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8193 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008194
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008195 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008196 eir_len = eir_append_data(ev->eir, eir_len,
8197 EIR_CLASS_OF_DEV,
8198 conn->dev_class, 3);
8199 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008200
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008201 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008202
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008203 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8204 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008205}
8206
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008207static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008208{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008209 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008210
Johan Hedbergf5818c22014-12-05 13:36:02 +02008211 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008212
8213 *sk = cmd->sk;
8214 sock_hold(*sk);
8215
Johan Hedberga664b5b2011-02-19 12:06:02 -03008216 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008217}
8218
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008219static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008220{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008221 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008222 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008223
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008224 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8225
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008226 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008227 mgmt_pending_remove(cmd);
8228}
8229
Johan Hedberg84c61d92014-08-01 11:13:30 +03008230bool mgmt_powering_down(struct hci_dev *hdev)
8231{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008232 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008233 struct mgmt_mode *cp;
8234
Johan Hedberg333ae952015-03-17 13:48:47 +02008235 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008236 if (!cmd)
8237 return false;
8238
8239 cp = cmd->param;
8240 if (!cp->val)
8241 return true;
8242
8243 return false;
8244}
8245
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008246void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008247 u8 link_type, u8 addr_type, u8 reason,
8248 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008249{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008250 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008251 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008252
Johan Hedberg84c61d92014-08-01 11:13:30 +03008253 /* The connection is still in hci_conn_hash so test for 1
8254 * instead of 0 to know if this is the last one.
8255 */
8256 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8257 cancel_delayed_work(&hdev->power_off);
8258 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008259 }
8260
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008261 if (!mgmt_connected)
8262 return;
8263
Andre Guedes57eb7762013-10-30 19:01:41 -03008264 if (link_type != ACL_LINK && link_type != LE_LINK)
8265 return;
8266
Johan Hedberg744cf192011-11-08 20:40:14 +02008267 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008268
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008269 bacpy(&ev.addr.bdaddr, bdaddr);
8270 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8271 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008272
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07008273 /* Report disconnects due to suspend */
8274 if (hdev->suspended)
8275 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
8276
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008277 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008278
8279 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008280 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008281
Johan Hedberg124f6e32012-02-09 13:50:12 +02008282 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008283 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008284}
8285
Marcel Holtmann78929242013-10-06 23:55:47 -07008286void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8287 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008288{
Andre Guedes3655bba2013-10-30 19:01:40 -03008289 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8290 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008291 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008292
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008293 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8294 hdev);
8295
Johan Hedberg333ae952015-03-17 13:48:47 +02008296 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008297 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008298 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008299
Andre Guedes3655bba2013-10-30 19:01:40 -03008300 cp = cmd->param;
8301
8302 if (bacmp(bdaddr, &cp->addr.bdaddr))
8303 return;
8304
8305 if (cp->addr.type != bdaddr_type)
8306 return;
8307
Johan Hedbergf5818c22014-12-05 13:36:02 +02008308 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008309 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008310}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008311
Marcel Holtmann445608d2013-10-06 23:55:48 -07008312void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8313 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008314{
8315 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008316
Johan Hedberg84c61d92014-08-01 11:13:30 +03008317 /* The connection is still in hci_conn_hash so test for 1
8318 * instead of 0 to know if this is the last one.
8319 */
8320 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8321 cancel_delayed_work(&hdev->power_off);
8322 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008323 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008324
Johan Hedberg4c659c32011-11-07 23:13:39 +02008325 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008326 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008327 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008328
Marcel Holtmann445608d2013-10-06 23:55:48 -07008329 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008330}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008331
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008332void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008333{
8334 struct mgmt_ev_pin_code_request ev;
8335
Johan Hedbergd8457692012-02-17 14:24:57 +02008336 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008337 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008338 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008339
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008340 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008341}
8342
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008343void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8344 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008345{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008346 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008347
Johan Hedberg333ae952015-03-17 13:48:47 +02008348 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008349 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008350 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008351
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008352 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008353 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008354}
8355
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008356void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8357 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008358{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008359 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008360
Johan Hedberg333ae952015-03-17 13:48:47 +02008361 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008362 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008363 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008364
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008365 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008366 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008367}
Johan Hedberga5c29682011-02-19 12:05:57 -03008368
Johan Hedberg744cf192011-11-08 20:40:14 +02008369int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008370 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008371 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008372{
8373 struct mgmt_ev_user_confirm_request ev;
8374
Marcel Holtmann181d6952020-05-06 09:57:47 +02008375 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008376
Johan Hedberg272d90d2012-02-09 15:26:12 +02008377 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008378 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008379 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008380 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008381
Johan Hedberg744cf192011-11-08 20:40:14 +02008382 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008383 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008384}
8385
Johan Hedberg272d90d2012-02-09 15:26:12 +02008386int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008387 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008388{
8389 struct mgmt_ev_user_passkey_request ev;
8390
Marcel Holtmann181d6952020-05-06 09:57:47 +02008391 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008392
Johan Hedberg272d90d2012-02-09 15:26:12 +02008393 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008394 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008395
8396 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008397 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008398}
8399
Brian Gix0df4c182011-11-16 13:53:13 -08008400static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008401 u8 link_type, u8 addr_type, u8 status,
8402 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008403{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008404 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008405
Johan Hedberg333ae952015-03-17 13:48:47 +02008406 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008407 if (!cmd)
8408 return -ENOENT;
8409
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008410 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008411 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008412
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008413 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008414}
8415
Johan Hedberg744cf192011-11-08 20:40:14 +02008416int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008417 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008418{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008419 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008420 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008421}
8422
Johan Hedberg272d90d2012-02-09 15:26:12 +02008423int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008424 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008425{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008426 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008427 status,
8428 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008429}
Johan Hedberg2a611692011-02-19 12:06:00 -03008430
Brian Gix604086b2011-11-23 08:28:33 -08008431int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008432 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008433{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008434 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008435 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008436}
8437
Johan Hedberg272d90d2012-02-09 15:26:12 +02008438int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008439 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008440{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008441 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008442 status,
8443 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008444}
8445
Johan Hedberg92a25252012-09-06 18:39:26 +03008446int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8447 u8 link_type, u8 addr_type, u32 passkey,
8448 u8 entered)
8449{
8450 struct mgmt_ev_passkey_notify ev;
8451
Marcel Holtmann181d6952020-05-06 09:57:47 +02008452 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008453
8454 bacpy(&ev.addr.bdaddr, bdaddr);
8455 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8456 ev.passkey = __cpu_to_le32(passkey);
8457 ev.entered = entered;
8458
8459 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8460}
8461
Johan Hedberge1e930f2014-09-08 17:09:49 -07008462void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008463{
8464 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008465 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008466 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008467
Johan Hedberge1e930f2014-09-08 17:09:49 -07008468 bacpy(&ev.addr.bdaddr, &conn->dst);
8469 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8470 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008471
Johan Hedberge1e930f2014-09-08 17:09:49 -07008472 cmd = find_pairing(conn);
8473
8474 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8475 cmd ? cmd->sk : NULL);
8476
Johan Hedberga511b352014-12-11 21:45:45 +02008477 if (cmd) {
8478 cmd->cmd_complete(cmd, status);
8479 mgmt_pending_remove(cmd);
8480 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008481}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008482
Marcel Holtmann464996a2013-10-15 14:26:24 -07008483void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008484{
8485 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008486 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008487
8488 if (status) {
8489 u8 mgmt_err = mgmt_status(status);
8490 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008491 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008492 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008493 }
8494
Marcel Holtmann464996a2013-10-15 14:26:24 -07008495 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008496 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008497 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008498 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008499
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008500 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008501 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008502
Johan Hedberg47990ea2012-02-22 11:58:37 +02008503 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008504 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008505
8506 if (match.sk)
8507 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008508}
8509
Johan Hedberg890ea892013-03-15 17:06:52 -05008510static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008511{
Johan Hedberg890ea892013-03-15 17:06:52 -05008512 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008513 struct hci_cp_write_eir cp;
8514
Johan Hedberg976eb202012-10-24 21:12:01 +03008515 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008516 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008517
Johan Hedbergc80da272012-02-22 15:38:48 +02008518 memset(hdev->eir, 0, sizeof(hdev->eir));
8519
Johan Hedbergcacaf522012-02-21 00:52:42 +02008520 memset(&cp, 0, sizeof(cp));
8521
Johan Hedberg890ea892013-03-15 17:06:52 -05008522 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008523}
8524
Marcel Holtmann3e248562013-10-15 14:26:25 -07008525void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008526{
8527 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008528 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008529 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008530
8531 if (status) {
8532 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008533
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008534 if (enable && hci_dev_test_and_clear_flag(hdev,
8535 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008536 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008537 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008538 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008539
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008540 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8541 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008542 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008543 }
8544
8545 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008546 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008547 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008548 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008549 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008550 changed = hci_dev_test_and_clear_flag(hdev,
8551 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008552 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008553 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008554 }
8555
8556 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8557
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008558 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008559 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008560
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008561 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008562 sock_put(match.sk);
8563
Johan Hedberg890ea892013-03-15 17:06:52 -05008564 hci_req_init(&req, hdev);
8565
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008566 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8567 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008568 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8569 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008570 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008571 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008572 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008573 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008574
8575 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008576}
8577
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008578static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008579{
8580 struct cmd_lookup *match = data;
8581
Johan Hedberg90e70452012-02-23 23:09:40 +02008582 if (match->sk == NULL) {
8583 match->sk = cmd->sk;
8584 sock_hold(match->sk);
8585 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008586}
8587
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008588void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8589 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008590{
Johan Hedberg90e70452012-02-23 23:09:40 +02008591 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008592
Johan Hedberg92da6092013-03-15 17:06:55 -05008593 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8594 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8595 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008596
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008597 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008598 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8599 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008600 ext_info_changed(hdev, NULL);
8601 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008602
8603 if (match.sk)
8604 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008605}
8606
Marcel Holtmann7667da32013-10-15 14:26:27 -07008607void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008608{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008609 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008610 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008611
Johan Hedberg13928972013-03-15 17:07:00 -05008612 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008613 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008614
8615 memset(&ev, 0, sizeof(ev));
8616 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008617 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008618
Johan Hedberg333ae952015-03-17 13:48:47 +02008619 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008620 if (!cmd) {
8621 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008622
Johan Hedberg13928972013-03-15 17:07:00 -05008623 /* If this is a HCI command related to powering on the
8624 * HCI dev don't send any mgmt signals.
8625 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008626 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008627 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008628 }
8629
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008630 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8631 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008632 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008633}
Szymon Jancc35938b2011-03-22 13:12:21 +01008634
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008635static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8636{
8637 int i;
8638
8639 for (i = 0; i < uuid_count; i++) {
8640 if (!memcmp(uuid, uuids[i], 16))
8641 return true;
8642 }
8643
8644 return false;
8645}
8646
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008647static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8648{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008649 u16 parsed = 0;
8650
8651 while (parsed < eir_len) {
8652 u8 field_len = eir[0];
8653 u8 uuid[16];
8654 int i;
8655
8656 if (field_len == 0)
8657 break;
8658
8659 if (eir_len - parsed < field_len + 1)
8660 break;
8661
8662 switch (eir[1]) {
8663 case EIR_UUID16_ALL:
8664 case EIR_UUID16_SOME:
8665 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008666 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008667 uuid[13] = eir[i + 3];
8668 uuid[12] = eir[i + 2];
8669 if (has_uuid(uuid, uuid_count, uuids))
8670 return true;
8671 }
8672 break;
8673 case EIR_UUID32_ALL:
8674 case EIR_UUID32_SOME:
8675 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008676 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008677 uuid[15] = eir[i + 5];
8678 uuid[14] = eir[i + 4];
8679 uuid[13] = eir[i + 3];
8680 uuid[12] = eir[i + 2];
8681 if (has_uuid(uuid, uuid_count, uuids))
8682 return true;
8683 }
8684 break;
8685 case EIR_UUID128_ALL:
8686 case EIR_UUID128_SOME:
8687 for (i = 0; i + 17 <= field_len; i += 16) {
8688 memcpy(uuid, eir + i + 2, 16);
8689 if (has_uuid(uuid, uuid_count, uuids))
8690 return true;
8691 }
8692 break;
8693 }
8694
8695 parsed += field_len + 1;
8696 eir += field_len + 1;
8697 }
8698
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008699 return false;
8700}
8701
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008702static void restart_le_scan(struct hci_dev *hdev)
8703{
8704 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008705 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008706 return;
8707
8708 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8709 hdev->discovery.scan_start +
8710 hdev->discovery.scan_duration))
8711 return;
8712
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008713 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008714 DISCOV_LE_RESTART_DELAY);
8715}
8716
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008717static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8718 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8719{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008720 /* If a RSSI threshold has been specified, and
8721 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8722 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8723 * is set, let it through for further processing, as we might need to
8724 * restart the scan.
8725 *
8726 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8727 * the results are also dropped.
8728 */
8729 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8730 (rssi == HCI_RSSI_INVALID ||
8731 (rssi < hdev->discovery.rssi &&
8732 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8733 return false;
8734
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008735 if (hdev->discovery.uuid_count != 0) {
8736 /* If a list of UUIDs is provided in filter, results with no
8737 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008738 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008739 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8740 hdev->discovery.uuids) &&
8741 !eir_has_uuids(scan_rsp, scan_rsp_len,
8742 hdev->discovery.uuid_count,
8743 hdev->discovery.uuids))
8744 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008745 }
8746
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008747 /* If duplicate filtering does not report RSSI changes, then restart
8748 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008749 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008750 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8751 restart_le_scan(hdev);
8752
8753 /* Validate RSSI value against the RSSI threshold once more. */
8754 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8755 rssi < hdev->discovery.rssi)
8756 return false;
8757 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008758
8759 return true;
8760}
8761
Marcel Holtmann901801b2013-10-06 23:55:51 -07008762void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008763 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8764 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008765{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008766 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008767 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008768 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008769
Johan Hedberg75ce2082014-07-02 22:42:01 +03008770 /* Don't send events for a non-kernel initiated discovery. With
8771 * LE one exception is if we have pend_le_reports > 0 in which
8772 * case we're doing passive scanning and want these events.
8773 */
8774 if (!hci_discovery_active(hdev)) {
8775 if (link_type == ACL_LINK)
8776 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008777 if (link_type == LE_LINK &&
8778 list_empty(&hdev->pend_le_reports) &&
8779 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03008780 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008781 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03008782 }
Andre Guedes12602d02013-04-30 15:29:40 -03008783
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008784 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008785 /* We are using service discovery */
8786 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8787 scan_rsp_len))
8788 return;
8789 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008790
Johan Hedberg78b781c2016-01-05 13:19:32 +02008791 if (hdev->discovery.limited) {
8792 /* Check for limited discoverable bit */
8793 if (dev_class) {
8794 if (!(dev_class[1] & 0x20))
8795 return;
8796 } else {
8797 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8798 if (!flags || !(flags[0] & LE_AD_LIMITED))
8799 return;
8800 }
8801 }
8802
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008803 /* Make sure that the buffer is big enough. The 5 extra bytes
8804 * are for the potential CoD field.
8805 */
8806 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008807 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008808
Johan Hedberg1dc06092012-01-15 21:01:23 +02008809 memset(buf, 0, sizeof(buf));
8810
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008811 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8812 * RSSI value was reported as 0 when not available. This behavior
8813 * is kept when using device discovery. This is required for full
8814 * backwards compatibility with the API.
8815 *
8816 * However when using service discovery, the value 127 will be
8817 * returned when the RSSI is not available.
8818 */
Szymon Janc91200e92015-01-22 16:57:05 +01008819 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8820 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008821 rssi = 0;
8822
Johan Hedberg841c5642014-07-07 12:45:54 +03008823 bacpy(&ev->addr.bdaddr, bdaddr);
8824 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008825 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008826 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008827
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008828 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008829 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008830 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008831
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008832 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8833 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008834 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008835 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008836
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008837 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008838 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008839 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008840
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008841 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8842 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008843
Marcel Holtmann901801b2013-10-06 23:55:51 -07008844 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008845}
Johan Hedberga88a9652011-03-30 13:18:12 +03008846
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008847void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8848 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008849{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008850 struct mgmt_ev_device_found *ev;
8851 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8852 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008853
Johan Hedbergb644ba32012-01-17 21:48:47 +02008854 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008855
Johan Hedbergb644ba32012-01-17 21:48:47 +02008856 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008857
Johan Hedbergb644ba32012-01-17 21:48:47 +02008858 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008859 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008860 ev->rssi = rssi;
8861
8862 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008863 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008864
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008865 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008866
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008867 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008868}
Johan Hedberg314b2382011-04-27 10:29:57 -04008869
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008870void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008871{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008872 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008873
Marcel Holtmann181d6952020-05-06 09:57:47 +02008874 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008875
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008876 memset(&ev, 0, sizeof(ev));
8877 ev.type = hdev->discovery.type;
8878 ev.discovering = discovering;
8879
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008880 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008881}
Antti Julku5e762442011-08-25 16:48:02 +03008882
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07008883void mgmt_suspending(struct hci_dev *hdev, u8 state)
8884{
8885 struct mgmt_ev_controller_suspend ev;
8886
8887 ev.suspend_state = state;
8888 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
8889}
8890
8891void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
8892 u8 addr_type)
8893{
8894 struct mgmt_ev_controller_resume ev;
8895
8896 ev.wake_reason = reason;
8897 if (bdaddr) {
8898 bacpy(&ev.addr.bdaddr, bdaddr);
8899 ev.addr.type = addr_type;
8900 } else {
8901 memset(&ev.addr, 0, sizeof(ev.addr));
8902 }
8903
8904 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
8905}
8906
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008907static struct hci_mgmt_chan chan = {
8908 .channel = HCI_CHANNEL_CONTROL,
8909 .handler_count = ARRAY_SIZE(mgmt_handlers),
8910 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008911 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008912};
8913
8914int mgmt_init(void)
8915{
8916 return hci_mgmt_chan_register(&chan);
8917}
8918
8919void mgmt_exit(void)
8920{
8921 hci_mgmt_chan_unregister(&chan);
8922}