blob: 5bbe71002fb9503caf087dfcfed6bec33dcd2cbb [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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200166};
167
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700168static const u16 mgmt_untrusted_commands[] = {
169 MGMT_OP_READ_INDEX_LIST,
170 MGMT_OP_READ_INFO,
171 MGMT_OP_READ_UNCONF_INDEX_LIST,
172 MGMT_OP_READ_CONFIG_INFO,
173 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200174 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200175 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200176 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000177 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200178 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700179};
180
181static const u16 mgmt_untrusted_events[] = {
182 MGMT_EV_INDEX_ADDED,
183 MGMT_EV_INDEX_REMOVED,
184 MGMT_EV_NEW_SETTINGS,
185 MGMT_EV_CLASS_OF_DEV_CHANGED,
186 MGMT_EV_LOCAL_NAME_CHANGED,
187 MGMT_EV_UNCONF_INDEX_ADDED,
188 MGMT_EV_UNCONF_INDEX_REMOVED,
189 MGMT_EV_NEW_CONFIG_OPTIONS,
190 MGMT_EV_EXT_INDEX_ADDED,
191 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200192 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200193 MGMT_EV_EXP_FEATURE_CHANGED,
Miao-chen Choub52729f2020-06-17 16:39:16 +0200194 MGMT_EV_ADV_MONITOR_ADDED,
Miao-chen Choucdde92e2020-06-17 16:39:17 +0200195 MGMT_EV_ADV_MONITOR_REMOVED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700196};
197
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800198#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200199
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200200#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
201 "\x00\x00\x00\x00\x00\x00\x00\x00"
202
Johan Hedbergca69b792011-11-11 18:10:00 +0200203/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000204static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200205 MGMT_STATUS_SUCCESS,
206 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
207 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
208 MGMT_STATUS_FAILED, /* Hardware Failure */
209 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
210 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200211 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200212 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
213 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
214 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
215 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
216 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
217 MGMT_STATUS_BUSY, /* Command Disallowed */
218 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
219 MGMT_STATUS_REJECTED, /* Rejected Security */
220 MGMT_STATUS_REJECTED, /* Rejected Personal */
221 MGMT_STATUS_TIMEOUT, /* Host Timeout */
222 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
223 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
224 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
225 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
226 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
227 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
228 MGMT_STATUS_BUSY, /* Repeated Attempts */
229 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
230 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
231 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
232 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
233 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
234 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
235 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
236 MGMT_STATUS_FAILED, /* Unspecified Error */
237 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
238 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
239 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
240 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
241 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
242 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
243 MGMT_STATUS_FAILED, /* Unit Link Key Used */
244 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
245 MGMT_STATUS_TIMEOUT, /* Instant Passed */
246 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
247 MGMT_STATUS_FAILED, /* Transaction Collision */
248 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
249 MGMT_STATUS_REJECTED, /* QoS Rejected */
250 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
251 MGMT_STATUS_REJECTED, /* Insufficient Security */
252 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
253 MGMT_STATUS_BUSY, /* Role Switch Pending */
254 MGMT_STATUS_FAILED, /* Slot Violation */
255 MGMT_STATUS_FAILED, /* Role Switch Failed */
256 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
257 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
258 MGMT_STATUS_BUSY, /* Host Busy Pairing */
259 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
260 MGMT_STATUS_BUSY, /* Controller Busy */
261 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
262 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
263 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
264 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
265 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
266};
267
268static u8 mgmt_status(u8 hci_status)
269{
270 if (hci_status < ARRAY_SIZE(mgmt_status_table))
271 return mgmt_status_table[hci_status];
272
273 return MGMT_STATUS_FAILED;
274}
275
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700276static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
277 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700278{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700279 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
280 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700281}
282
Marcel Holtmann72000df2015-03-16 16:11:21 -0700283static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
284 u16 len, int flag, struct sock *skip_sk)
285{
286 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
287 flag, skip_sk);
288}
289
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200290static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
291 struct sock *skip_sk)
292{
293 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700294 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200295}
296
Johan Hedberg85813a72015-10-21 18:02:59 +0300297static u8 le_addr_type(u8 mgmt_addr_type)
298{
299 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
300 return ADDR_LE_DEV_PUBLIC;
301 else
302 return ADDR_LE_DEV_RANDOM;
303}
304
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200305void mgmt_fill_version_info(void *ver)
306{
307 struct mgmt_rp_read_version *rp = ver;
308
309 rp->version = MGMT_VERSION;
310 rp->revision = cpu_to_le16(MGMT_REVISION);
311}
312
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
314 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200315{
316 struct mgmt_rp_read_version rp;
317
Marcel Holtmann181d6952020-05-06 09:57:47 +0200318 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200319
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200320 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200321
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200322 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
323 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200324}
325
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300326static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
327 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328{
329 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700330 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200331 size_t rp_size;
332 int i, err;
333
Marcel Holtmann181d6952020-05-06 09:57:47 +0200334 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200335
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700336 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
337 num_commands = ARRAY_SIZE(mgmt_commands);
338 num_events = ARRAY_SIZE(mgmt_events);
339 } else {
340 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
341 num_events = ARRAY_SIZE(mgmt_untrusted_events);
342 }
343
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200344 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
345
346 rp = kmalloc(rp_size, GFP_KERNEL);
347 if (!rp)
348 return -ENOMEM;
349
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700350 rp->num_commands = cpu_to_le16(num_commands);
351 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200352
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700353 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
354 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200355
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700356 for (i = 0; i < num_commands; i++, opcode++)
357 put_unaligned_le16(mgmt_commands[i], opcode);
358
359 for (i = 0; i < num_events; i++, opcode++)
360 put_unaligned_le16(mgmt_events[i], opcode);
361 } else {
362 __le16 *opcode = rp->opcodes;
363
364 for (i = 0; i < num_commands; i++, opcode++)
365 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
366
367 for (i = 0; i < num_events; i++, opcode++)
368 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
369 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200370
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200371 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
372 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200373 kfree(rp);
374
375 return err;
376}
377
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300378static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
379 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200381 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200382 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200383 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200384 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300385 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200386
Marcel Holtmann181d6952020-05-06 09:57:47 +0200387 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200388
389 read_lock(&hci_dev_list_lock);
390
391 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300392 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200393 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700394 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700395 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 }
397
Johan Hedberga38528f2011-01-22 06:46:43 +0200398 rp_len = sizeof(*rp) + (2 * count);
399 rp = kmalloc(rp_len, GFP_ATOMIC);
400 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100401 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100403 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404
Johan Hedberg476e44c2012-10-19 20:10:46 +0300405 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200406 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700407 if (hci_dev_test_flag(d, HCI_SETUP) ||
408 hci_dev_test_flag(d, HCI_CONFIG) ||
409 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200410 continue;
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412 /* Devices marked as raw-only are neither configured
413 * nor unconfigured controllers.
414 */
415 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700416 continue;
417
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200418 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700419 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700420 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200421 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700422 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200423 }
424
Johan Hedberg476e44c2012-10-19 20:10:46 +0300425 rp->num_controllers = cpu_to_le16(count);
426 rp_len = sizeof(*rp) + (2 * count);
427
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428 read_unlock(&hci_dev_list_lock);
429
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200430 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
431 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200432
Johan Hedberga38528f2011-01-22 06:46:43 +0200433 kfree(rp);
434
435 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200436}
437
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
439 void *data, u16 data_len)
440{
441 struct mgmt_rp_read_unconf_index_list *rp;
442 struct hci_dev *d;
443 size_t rp_len;
444 u16 count;
445 int err;
446
Marcel Holtmann181d6952020-05-06 09:57:47 +0200447 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448
449 read_lock(&hci_dev_list_lock);
450
451 count = 0;
452 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200453 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700454 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200455 count++;
456 }
457
458 rp_len = sizeof(*rp) + (2 * count);
459 rp = kmalloc(rp_len, GFP_ATOMIC);
460 if (!rp) {
461 read_unlock(&hci_dev_list_lock);
462 return -ENOMEM;
463 }
464
465 count = 0;
466 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700467 if (hci_dev_test_flag(d, HCI_SETUP) ||
468 hci_dev_test_flag(d, HCI_CONFIG) ||
469 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200470 continue;
471
472 /* Devices marked as raw-only are neither configured
473 * nor unconfigured controllers.
474 */
475 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
476 continue;
477
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200478 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700479 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200480 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200481 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200482 }
483 }
484
485 rp->num_controllers = cpu_to_le16(count);
486 rp_len = sizeof(*rp) + (2 * count);
487
488 read_unlock(&hci_dev_list_lock);
489
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200490 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
491 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200492
493 kfree(rp);
494
495 return err;
496}
497
Marcel Holtmann96f14742015-03-14 19:27:57 -0700498static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
499 void *data, u16 data_len)
500{
501 struct mgmt_rp_read_ext_index_list *rp;
502 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700503 u16 count;
504 int err;
505
Marcel Holtmann181d6952020-05-06 09:57:47 +0200506 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700507
508 read_lock(&hci_dev_list_lock);
509
510 count = 0;
511 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200512 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700513 count++;
514 }
515
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600516 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700517 if (!rp) {
518 read_unlock(&hci_dev_list_lock);
519 return -ENOMEM;
520 }
521
522 count = 0;
523 list_for_each_entry(d, &hci_dev_list, list) {
524 if (hci_dev_test_flag(d, HCI_SETUP) ||
525 hci_dev_test_flag(d, HCI_CONFIG) ||
526 hci_dev_test_flag(d, HCI_USER_CHANNEL))
527 continue;
528
529 /* Devices marked as raw-only are neither configured
530 * nor unconfigured controllers.
531 */
532 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
533 continue;
534
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200535 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700536 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
537 rp->entry[count].type = 0x01;
538 else
539 rp->entry[count].type = 0x00;
540 } else if (d->dev_type == HCI_AMP) {
541 rp->entry[count].type = 0x02;
542 } else {
543 continue;
544 }
545
546 rp->entry[count].bus = d->bus;
547 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200548 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700549 }
550
551 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700552
553 read_unlock(&hci_dev_list_lock);
554
555 /* If this command is called at least once, then all the
556 * default index and unconfigured index events are disabled
557 * and from now on only extended index events are used.
558 */
559 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
560 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
561 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
562
563 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600564 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
565 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700566
567 kfree(rp);
568
569 return err;
570}
571
Marcel Holtmanndbece372014-07-04 18:11:55 +0200572static bool is_configured(struct hci_dev *hdev)
573{
574 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700575 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200576 return false;
577
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800578 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
579 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200580 !bacmp(&hdev->public_addr, BDADDR_ANY))
581 return false;
582
583 return true;
584}
585
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200586static __le32 get_missing_options(struct hci_dev *hdev)
587{
588 u32 options = 0;
589
Marcel Holtmanndbece372014-07-04 18:11:55 +0200590 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700591 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200592 options |= MGMT_OPTION_EXTERNAL_CONFIG;
593
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800594 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
595 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200596 !bacmp(&hdev->public_addr, BDADDR_ANY))
597 options |= MGMT_OPTION_PUBLIC_ADDRESS;
598
599 return cpu_to_le32(options);
600}
601
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200602static int new_options(struct hci_dev *hdev, struct sock *skip)
603{
604 __le32 options = get_missing_options(hdev);
605
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200606 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
607 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200608}
609
Marcel Holtmanndbece372014-07-04 18:11:55 +0200610static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
611{
612 __le32 options = get_missing_options(hdev);
613
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200614 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
615 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200616}
617
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200618static int read_config_info(struct sock *sk, struct hci_dev *hdev,
619 void *data, u16 data_len)
620{
621 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200622 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200623
Marcel Holtmann181d6952020-05-06 09:57:47 +0200624 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200625
626 hci_dev_lock(hdev);
627
628 memset(&rp, 0, sizeof(rp));
629 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200630
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200631 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
632 options |= MGMT_OPTION_EXTERNAL_CONFIG;
633
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200634 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200635 options |= MGMT_OPTION_PUBLIC_ADDRESS;
636
637 rp.supported_options = cpu_to_le32(options);
638 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200639
640 hci_dev_unlock(hdev);
641
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200642 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
643 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200644}
645
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530646static u32 get_supported_phys(struct hci_dev *hdev)
647{
648 u32 supported_phys = 0;
649
650 if (lmp_bredr_capable(hdev)) {
651 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
652
653 if (hdev->features[0][0] & LMP_3SLOT)
654 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
655
656 if (hdev->features[0][0] & LMP_5SLOT)
657 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
658
659 if (lmp_edr_2m_capable(hdev)) {
660 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
661
662 if (lmp_edr_3slot_capable(hdev))
663 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
664
665 if (lmp_edr_5slot_capable(hdev))
666 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
667
668 if (lmp_edr_3m_capable(hdev)) {
669 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
670
671 if (lmp_edr_3slot_capable(hdev))
672 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
673
674 if (lmp_edr_5slot_capable(hdev))
675 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
676 }
677 }
678 }
679
680 if (lmp_le_capable(hdev)) {
681 supported_phys |= MGMT_PHY_LE_1M_TX;
682 supported_phys |= MGMT_PHY_LE_1M_RX;
683
684 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
685 supported_phys |= MGMT_PHY_LE_2M_TX;
686 supported_phys |= MGMT_PHY_LE_2M_RX;
687 }
688
689 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
690 supported_phys |= MGMT_PHY_LE_CODED_TX;
691 supported_phys |= MGMT_PHY_LE_CODED_RX;
692 }
693 }
694
695 return supported_phys;
696}
697
698static u32 get_selected_phys(struct hci_dev *hdev)
699{
700 u32 selected_phys = 0;
701
702 if (lmp_bredr_capable(hdev)) {
703 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
704
705 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
706 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
707
708 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
709 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
710
711 if (lmp_edr_2m_capable(hdev)) {
712 if (!(hdev->pkt_type & HCI_2DH1))
713 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
714
715 if (lmp_edr_3slot_capable(hdev) &&
716 !(hdev->pkt_type & HCI_2DH3))
717 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
718
719 if (lmp_edr_5slot_capable(hdev) &&
720 !(hdev->pkt_type & HCI_2DH5))
721 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
722
723 if (lmp_edr_3m_capable(hdev)) {
724 if (!(hdev->pkt_type & HCI_3DH1))
725 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
726
727 if (lmp_edr_3slot_capable(hdev) &&
728 !(hdev->pkt_type & HCI_3DH3))
729 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
730
731 if (lmp_edr_5slot_capable(hdev) &&
732 !(hdev->pkt_type & HCI_3DH5))
733 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
734 }
735 }
736 }
737
738 if (lmp_le_capable(hdev)) {
739 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
740 selected_phys |= MGMT_PHY_LE_1M_TX;
741
742 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
743 selected_phys |= MGMT_PHY_LE_1M_RX;
744
745 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
746 selected_phys |= MGMT_PHY_LE_2M_TX;
747
748 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
749 selected_phys |= MGMT_PHY_LE_2M_RX;
750
751 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
752 selected_phys |= MGMT_PHY_LE_CODED_TX;
753
754 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
755 selected_phys |= MGMT_PHY_LE_CODED_RX;
756 }
757
758 return selected_phys;
759}
760
761static u32 get_configurable_phys(struct hci_dev *hdev)
762{
763 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
764 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
765}
766
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200768{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200769 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200770
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300772 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800773 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300774 settings |= MGMT_SETTING_CONNECTABLE;
775 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Andre Guedesed3fa312012-07-24 15:03:46 -0300777 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500778 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
779 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200780 settings |= MGMT_SETTING_BREDR;
781 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700782
783 if (lmp_ssp_capable(hdev)) {
784 settings |= MGMT_SETTING_SSP;
785 settings |= MGMT_SETTING_HS;
786 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800787
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800788 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800789 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000790
Alain Michaud00bce3f2020-03-05 16:14:59 +0000791 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000792 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000793 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700794 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100795
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300796 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200797 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300798 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200799 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800800 settings |= MGMT_SETTING_STATIC_ADDRESS;
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +0530801
802 /* When the experimental feature for LL Privacy support is
803 * enabled, then advertising is no longer supported.
804 */
805 if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
806 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300807 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200808
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200809 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
810 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200811 settings |= MGMT_SETTING_CONFIGURATION;
812
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530813 settings |= MGMT_SETTING_PHY_CONFIGURATION;
814
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200815 return settings;
816}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200817
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200818static u32 get_current_settings(struct hci_dev *hdev)
819{
820 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200821
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200822 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100823 settings |= MGMT_SETTING_POWERED;
824
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700825 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200826 settings |= MGMT_SETTING_CONNECTABLE;
827
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700828 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500829 settings |= MGMT_SETTING_FAST_CONNECTABLE;
830
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700831 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 settings |= MGMT_SETTING_DISCOVERABLE;
833
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700834 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300835 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200836
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700837 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200838 settings |= MGMT_SETTING_BREDR;
839
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700840 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200841 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200842
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700843 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200844 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200845
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700846 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200847 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200848
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700849 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200850 settings |= MGMT_SETTING_HS;
851
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700852 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300853 settings |= MGMT_SETTING_ADVERTISING;
854
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700855 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800856 settings |= MGMT_SETTING_SECURE_CONN;
857
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700858 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800859 settings |= MGMT_SETTING_DEBUG_KEYS;
860
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200862 settings |= MGMT_SETTING_PRIVACY;
863
Marcel Holtmann93690c22015-03-06 10:11:21 -0800864 /* The current setting for static address has two purposes. The
865 * first is to indicate if the static address will be used and
866 * the second is to indicate if it is actually set.
867 *
868 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700869 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800870 * address is actually used decides if the flag is set or not.
871 *
872 * For single mode LE only controllers and dual-mode controllers
873 * with BR/EDR disabled, the existence of the static address will
874 * be evaluated.
875 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700876 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700877 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800878 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
879 if (bacmp(&hdev->static_addr, BDADDR_ANY))
880 settings |= MGMT_SETTING_STATIC_ADDRESS;
881 }
882
Alain Michaud00bce3f2020-03-05 16:14:59 +0000883 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
884 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
885
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200886 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200887}
888
Johan Hedberg333ae952015-03-17 13:48:47 +0200889static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
890{
891 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
892}
893
Johan Hedberg333ae952015-03-17 13:48:47 +0200894static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
895 struct hci_dev *hdev,
896 const void *data)
897{
898 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
899}
900
Johan Hedbergf2252572015-11-18 12:49:20 +0200901u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300902{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200903 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300904
905 /* If there's a pending mgmt command the flags will not yet have
906 * their final values, so check for this first.
907 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200908 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300909 if (cmd) {
910 struct mgmt_mode *cp = cmd->param;
911 if (cp->val == 0x01)
912 return LE_AD_GENERAL;
913 else if (cp->val == 0x02)
914 return LE_AD_LIMITED;
915 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700916 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300917 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700918 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300919 return LE_AD_GENERAL;
920 }
921
922 return 0;
923}
924
Johan Hedbergf2252572015-11-18 12:49:20 +0200925bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700926{
927 struct mgmt_pending_cmd *cmd;
928
929 /* If there's a pending mgmt command the flag will not yet have
930 * it's final value, so check for this first.
931 */
932 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
933 if (cmd) {
934 struct mgmt_mode *cp = cmd->param;
935
936 return cp->val;
937 }
938
939 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
940}
941
Johan Hedberg7d785252011-12-15 00:47:39 +0200942static void service_cache_off(struct work_struct *work)
943{
944 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500946 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200947
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700948 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200949 return;
950
Johan Hedberg890ea892013-03-15 17:06:52 -0500951 hci_req_init(&req, hdev);
952
Johan Hedberg7d785252011-12-15 00:47:39 +0200953 hci_dev_lock(hdev);
954
Johan Hedbergb1a89172015-11-25 16:15:42 +0200955 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200956 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200957
958 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500959
960 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200961}
962
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200963static void rpa_expired(struct work_struct *work)
964{
965 struct hci_dev *hdev = container_of(work, struct hci_dev,
966 rpa_expired.work);
967 struct hci_request req;
968
Marcel Holtmann181d6952020-05-06 09:57:47 +0200969 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200970
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700971 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200972
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700973 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200974 return;
975
976 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200977 * controller happens in the hci_req_enable_advertising()
978 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200979 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200980 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530981 if (ext_adv_capable(hdev))
982 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
983 else
984 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200985 hci_req_run(&req, NULL);
986}
987
Johan Hedberg6a919082012-02-28 06:17:26 +0200988static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200989{
Marcel Holtmann238be782015-03-13 02:11:06 -0700990 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200991 return;
992
Johan Hedberg4f87da82012-03-02 19:55:56 +0200993 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200994 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200995
Johan Hedberg4f87da82012-03-02 19:55:56 +0200996 /* Non-mgmt controlled devices get this bit set
997 * implicitly so that pairing works for them, however
998 * for mgmt we require user-space to explicitly enable
999 * it
1000 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001001 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001002}
1003
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001004static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001005 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001006{
1007 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001008
Marcel Holtmann181d6952020-05-06 09:57:47 +02001009 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001010
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001011 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001012
Johan Hedberg03811012010-12-08 00:21:06 +02001013 memset(&rp, 0, sizeof(rp));
1014
Johan Hedberg03811012010-12-08 00:21:06 +02001015 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001016
1017 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001018 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001019
1020 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1021 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1022
1023 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001024
1025 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001026 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001029
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001030 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1031 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001032}
1033
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001034static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1035{
1036 u16 eir_len = 0;
1037 size_t name_len;
1038
1039 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1040 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1041 hdev->dev_class, 3);
1042
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001043 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1044 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1045 hdev->appearance);
1046
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001047 name_len = strlen(hdev->dev_name);
1048 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1049 hdev->dev_name, name_len);
1050
1051 name_len = strlen(hdev->short_name);
1052 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1053 hdev->short_name, name_len);
1054
1055 return eir_len;
1056}
1057
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001058static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1059 void *data, u16 data_len)
1060{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001061 char buf[512];
1062 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001063 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001064
Marcel Holtmann181d6952020-05-06 09:57:47 +02001065 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001066
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001067 memset(&buf, 0, sizeof(buf));
1068
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001069 hci_dev_lock(hdev);
1070
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001071 bacpy(&rp->bdaddr, &hdev->bdaddr);
1072
1073 rp->version = hdev->hci_ver;
1074 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1075
1076 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1077 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001078
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001079
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001080 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001081 rp->eir_len = cpu_to_le16(eir_len);
1082
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001083 hci_dev_unlock(hdev);
1084
1085 /* If this command is called at least once, then the events
1086 * for class of device and local name changes are disabled
1087 * and only the new extended controller information event
1088 * is used.
1089 */
1090 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1091 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1092 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1093
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001094 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1095 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001096}
1097
1098static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1099{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001100 char buf[512];
1101 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1102 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001103
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001104 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001105
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001106 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1107 ev->eir_len = cpu_to_le16(eir_len);
1108
1109 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1110 sizeof(*ev) + eir_len,
1111 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001112}
1113
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001114static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001115{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001116 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001117
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001118 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1119 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001120}
1121
Marcel Holtmann1904a852015-01-11 13:50:44 -08001122static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001123{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001124 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001125
Johan Hedberga3172b72014-02-28 09:33:44 +02001126 if (hci_conn_count(hdev) == 0) {
1127 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001128 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001129 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001130}
1131
Johan Hedbergf2252572015-11-18 12:49:20 +02001132void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001133{
1134 struct mgmt_ev_advertising_added ev;
1135
1136 ev.instance = instance;
1137
1138 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1139}
1140
Johan Hedbergf2252572015-11-18 12:49:20 +02001141void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1142 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001143{
1144 struct mgmt_ev_advertising_removed ev;
1145
1146 ev.instance = instance;
1147
1148 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1149}
1150
Florian Grandel7816b822015-06-18 03:16:45 +02001151static void cancel_adv_timeout(struct hci_dev *hdev)
1152{
1153 if (hdev->adv_instance_timeout) {
1154 hdev->adv_instance_timeout = 0;
1155 cancel_delayed_work(&hdev->adv_instance_expire);
1156 }
1157}
1158
Johan Hedberg8b064a32014-02-24 14:52:22 +02001159static int clean_up_hci_state(struct hci_dev *hdev)
1160{
1161 struct hci_request req;
1162 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001163 bool discov_stopped;
1164 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001165
1166 hci_req_init(&req, hdev);
1167
1168 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1169 test_bit(HCI_PSCAN, &hdev->flags)) {
1170 u8 scan = 0x00;
1171 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1172 }
1173
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001174 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001175
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001176 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001177 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001178
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001179 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001180
1181 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001182 /* 0x15 == Terminated due to Power Off */
1183 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001184 }
1185
Johan Hedberg23a48092014-07-08 16:05:06 +03001186 err = hci_req_run(&req, clean_up_hci_complete);
1187 if (!err && discov_stopped)
1188 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1189
1190 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001191}
1192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001194 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001196 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001197 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001198 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199
Marcel Holtmann181d6952020-05-06 09:57:47 +02001200 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201
Johan Hedberga7e80f22013-01-09 16:05:19 +02001202 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001203 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1204 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001205
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001206 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberg333ae952015-03-17 13:48:47 +02001208 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001209 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1210 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001211 goto failed;
1212 }
1213
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001214 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001215 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 goto failed;
1217 }
1218
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1220 if (!cmd) {
1221 err = -ENOMEM;
1222 goto failed;
1223 }
1224
Johan Hedberg8b064a32014-02-24 14:52:22 +02001225 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001226 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001227 err = 0;
1228 } else {
1229 /* Disconnect connections, stop scans, etc */
1230 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001231 if (!err)
1232 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1233 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001234
Johan Hedberg8b064a32014-02-24 14:52:22 +02001235 /* ENODATA means there were no HCI commands queued */
1236 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001237 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001238 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1239 err = 0;
1240 }
1241 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001242
1243failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001244 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001245 return err;
1246}
1247
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001248static int new_settings(struct hci_dev *hdev, struct sock *skip)
1249{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001250 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001251
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001252 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1253 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001254}
1255
Johan Hedberg91a668b2014-07-09 13:28:26 +03001256int mgmt_new_settings(struct hci_dev *hdev)
1257{
1258 return new_settings(hdev, NULL);
1259}
1260
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001261struct cmd_lookup {
1262 struct sock *sk;
1263 struct hci_dev *hdev;
1264 u8 mgmt_status;
1265};
1266
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001267static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001268{
1269 struct cmd_lookup *match = data;
1270
1271 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1272
1273 list_del(&cmd->list);
1274
1275 if (match->sk == NULL) {
1276 match->sk = cmd->sk;
1277 sock_hold(match->sk);
1278 }
1279
1280 mgmt_pending_free(cmd);
1281}
1282
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001283static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001284{
1285 u8 *status = data;
1286
Johan Hedberga69e8372015-03-06 21:08:53 +02001287 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001288 mgmt_pending_remove(cmd);
1289}
1290
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001291static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001292{
1293 if (cmd->cmd_complete) {
1294 u8 *status = data;
1295
1296 cmd->cmd_complete(cmd, *status);
1297 mgmt_pending_remove(cmd);
1298
1299 return;
1300 }
1301
1302 cmd_status_rsp(cmd, data);
1303}
1304
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001305static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001306{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001307 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1308 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001309}
1310
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001311static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001312{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001313 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1314 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001315}
1316
Johan Hedberge6fe7982013-10-02 15:45:22 +03001317static u8 mgmt_bredr_support(struct hci_dev *hdev)
1318{
1319 if (!lmp_bredr_capable(hdev))
1320 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001321 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001322 return MGMT_STATUS_REJECTED;
1323 else
1324 return MGMT_STATUS_SUCCESS;
1325}
1326
1327static u8 mgmt_le_support(struct hci_dev *hdev)
1328{
1329 if (!lmp_le_capable(hdev))
1330 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001331 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001332 return MGMT_STATUS_REJECTED;
1333 else
1334 return MGMT_STATUS_SUCCESS;
1335}
1336
Johan Hedbergaed1a882015-11-22 17:24:44 +03001337void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001338{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001339 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001340
Marcel Holtmann181d6952020-05-06 09:57:47 +02001341 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001342
1343 hci_dev_lock(hdev);
1344
Johan Hedberg333ae952015-03-17 13:48:47 +02001345 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001346 if (!cmd)
1347 goto unlock;
1348
1349 if (status) {
1350 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001351 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001352 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001353 goto remove_cmd;
1354 }
1355
Johan Hedbergaed1a882015-11-22 17:24:44 +03001356 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1357 hdev->discov_timeout > 0) {
1358 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1359 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001360 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001361
1362 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001363 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001364
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001365remove_cmd:
1366 mgmt_pending_remove(cmd);
1367
1368unlock:
1369 hci_dev_unlock(hdev);
1370}
1371
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001373 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001374{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001375 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001376 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001377 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001378 int err;
1379
Marcel Holtmann181d6952020-05-06 09:57:47 +02001380 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001381
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001382 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1383 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001384 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1385 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001386
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001387 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001388 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1389 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001390
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001391 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001392
1393 /* Disabling discoverable requires that no timeout is set,
1394 * and enabling limited discoverable requires a timeout.
1395 */
1396 if ((cp->val == 0x00 && timeout > 0) ||
1397 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001398 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001402
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001403 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001404 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1405 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001406 goto failed;
1407 }
1408
Johan Hedberg333ae952015-03-17 13:48:47 +02001409 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1410 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001411 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1412 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001413 goto failed;
1414 }
1415
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001416 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1418 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001419 goto failed;
1420 }
1421
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001422 if (hdev->advertising_paused) {
1423 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1424 MGMT_STATUS_BUSY);
1425 goto failed;
1426 }
1427
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001428 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001429 bool changed = false;
1430
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001431 /* Setting limited discoverable when powered off is
1432 * not a valid operation since it requires a timeout
1433 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1434 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001435 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001436 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001437 changed = true;
1438 }
1439
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001440 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001441 if (err < 0)
1442 goto failed;
1443
1444 if (changed)
1445 err = new_settings(hdev, sk);
1446
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001447 goto failed;
1448 }
1449
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001450 /* If the current mode is the same, then just update the timeout
1451 * value with the new value. And if only the timeout gets updated,
1452 * then no need for any HCI transactions.
1453 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001454 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1455 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1456 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001457 cancel_delayed_work(&hdev->discov_off);
1458 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001459
Marcel Holtmann36261542013-10-15 08:28:51 -07001460 if (cp->val && hdev->discov_timeout > 0) {
1461 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001462 queue_delayed_work(hdev->req_workqueue,
1463 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001464 }
1465
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001466 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001467 goto failed;
1468 }
1469
1470 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1471 if (!cmd) {
1472 err = -ENOMEM;
1473 goto failed;
1474 }
1475
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001476 /* Cancel any potential discoverable timeout that might be
1477 * still active and store new timeout value. The arming of
1478 * the timeout happens in the complete handler.
1479 */
1480 cancel_delayed_work(&hdev->discov_off);
1481 hdev->discov_timeout = timeout;
1482
Johan Hedbergaed1a882015-11-22 17:24:44 +03001483 if (cp->val)
1484 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1485 else
1486 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1487
Johan Hedbergb456f872013-10-19 23:38:22 +03001488 /* Limited discoverable mode */
1489 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001490 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001491 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001492 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001493
Johan Hedbergaed1a882015-11-22 17:24:44 +03001494 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1495 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001496
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001497failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001499 return err;
1500}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001501
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001502void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001503{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001504 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001505
Marcel Holtmann181d6952020-05-06 09:57:47 +02001506 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001507
1508 hci_dev_lock(hdev);
1509
Johan Hedberg333ae952015-03-17 13:48:47 +02001510 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001511 if (!cmd)
1512 goto unlock;
1513
Johan Hedberg37438c12013-10-14 16:20:05 +03001514 if (status) {
1515 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001516 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001517 goto remove_cmd;
1518 }
1519
Johan Hedberg2b76f452013-03-15 17:07:04 -05001520 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001521 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001522
Johan Hedberg37438c12013-10-14 16:20:05 +03001523remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001524 mgmt_pending_remove(cmd);
1525
1526unlock:
1527 hci_dev_unlock(hdev);
1528}
1529
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001530static int set_connectable_update_settings(struct hci_dev *hdev,
1531 struct sock *sk, u8 val)
1532{
1533 bool changed = false;
1534 int err;
1535
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001536 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001537 changed = true;
1538
1539 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001540 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001541 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001542 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1543 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001544 }
1545
1546 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1547 if (err < 0)
1548 return err;
1549
Johan Hedberg562064e2014-07-08 16:35:34 +03001550 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001551 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001552 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001553 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001554 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001555
1556 return 0;
1557}
1558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001559static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001560 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001561{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001562 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001563 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001564 int err;
1565
Marcel Holtmann181d6952020-05-06 09:57:47 +02001566 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001567
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001568 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1569 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001570 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1571 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001572
Johan Hedberga7e80f22013-01-09 16:05:19 +02001573 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001574 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1575 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001576
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001578
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001579 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001580 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001581 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001582 }
1583
Johan Hedberg333ae952015-03-17 13:48:47 +02001584 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1585 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001586 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1587 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001588 goto failed;
1589 }
1590
Johan Hedberg73f22f62010-12-29 16:00:25 +02001591 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1592 if (!cmd) {
1593 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001594 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001595 }
1596
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001597 if (cp->val) {
1598 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1599 } else {
1600 if (hdev->discov_timeout > 0)
1601 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001602
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001603 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1604 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1605 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001606 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001607
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001608 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1609 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001610
1611failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001613 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001614}
1615
Johan Hedbergb2939472014-07-30 09:22:23 +03001616static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001617 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001618{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001619 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001620 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001621 int err;
1622
Marcel Holtmann181d6952020-05-06 09:57:47 +02001623 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001624
Johan Hedberga7e80f22013-01-09 16:05:19 +02001625 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001629 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001630
1631 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001632 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001633 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001634 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001635
Johan Hedbergb2939472014-07-30 09:22:23 +03001636 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001637 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001638 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001639
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001640 if (changed) {
1641 /* In limited privacy mode the change of bondable mode
1642 * may affect the local advertising address.
1643 */
1644 if (hdev_is_powered(hdev) &&
1645 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1646 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1647 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1648 queue_work(hdev->req_workqueue,
1649 &hdev->discoverable_update);
1650
Marcel Holtmann55594352013-10-06 16:11:57 -07001651 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001652 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001653
Marcel Holtmann55594352013-10-06 16:11:57 -07001654unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001655 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001656 return err;
1657}
1658
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1660 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001661{
1662 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001663 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001664 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001665 int err;
1666
Marcel Holtmann181d6952020-05-06 09:57:47 +02001667 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001668
Johan Hedberge6fe7982013-10-02 15:45:22 +03001669 status = mgmt_bredr_support(hdev);
1670 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001671 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1672 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001673
Johan Hedberga7e80f22013-01-09 16:05:19 +02001674 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001675 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1676 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001677
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001678 hci_dev_lock(hdev);
1679
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001680 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001681 bool changed = false;
1682
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001683 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001684 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001685 changed = true;
1686 }
1687
1688 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1689 if (err < 0)
1690 goto failed;
1691
1692 if (changed)
1693 err = new_settings(hdev, sk);
1694
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001695 goto failed;
1696 }
1697
Johan Hedberg333ae952015-03-17 13:48:47 +02001698 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001699 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1700 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001701 goto failed;
1702 }
1703
1704 val = !!cp->val;
1705
1706 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1707 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1708 goto failed;
1709 }
1710
1711 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1712 if (!cmd) {
1713 err = -ENOMEM;
1714 goto failed;
1715 }
1716
1717 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1718 if (err < 0) {
1719 mgmt_pending_remove(cmd);
1720 goto failed;
1721 }
1722
1723failed:
1724 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001725 return err;
1726}
1727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001729{
1730 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001731 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001732 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001733 int err;
1734
Marcel Holtmann181d6952020-05-06 09:57:47 +02001735 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001736
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001737 status = mgmt_bredr_support(hdev);
1738 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001739 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001740
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001741 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001742 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1743 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001744
Johan Hedberga7e80f22013-01-09 16:05:19 +02001745 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001746 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001748
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001749 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001750
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001751 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001752 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001753
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001754 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001755 changed = !hci_dev_test_and_set_flag(hdev,
1756 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001757 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001758 changed = hci_dev_test_and_clear_flag(hdev,
1759 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001760 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001761 changed = hci_dev_test_and_clear_flag(hdev,
1762 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001763 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001764 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001765 }
1766
1767 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1768 if (err < 0)
1769 goto failed;
1770
1771 if (changed)
1772 err = new_settings(hdev, sk);
1773
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001774 goto failed;
1775 }
1776
Johan Hedberg333ae952015-03-17 13:48:47 +02001777 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001778 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1779 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001780 goto failed;
1781 }
1782
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001783 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001784 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1785 goto failed;
1786 }
1787
1788 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1789 if (!cmd) {
1790 err = -ENOMEM;
1791 goto failed;
1792 }
1793
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001794 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001795 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1796 sizeof(cp->val), &cp->val);
1797
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001798 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001799 if (err < 0) {
1800 mgmt_pending_remove(cmd);
1801 goto failed;
1802 }
1803
1804failed:
1805 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001806 return err;
1807}
1808
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001809static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001810{
1811 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001812 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001813 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001814 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001815
Marcel Holtmann181d6952020-05-06 09:57:47 +02001816 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001817
Johan Hedberge6fe7982013-10-02 15:45:22 +03001818 status = mgmt_bredr_support(hdev);
1819 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001820 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001821
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001822 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001823 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1824 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001826 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001827 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1828 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001829
Johan Hedberga7e80f22013-01-09 16:05:19 +02001830 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001831 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1832 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001833
Marcel Holtmannee392692013-10-01 22:59:23 -07001834 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001835
Johan Hedberg333ae952015-03-17 13:48:47 +02001836 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001837 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1838 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001839 goto unlock;
1840 }
1841
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001842 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001843 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001844 } else {
1845 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001846 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1847 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001848 goto unlock;
1849 }
1850
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001851 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001852 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001853
1854 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1855 if (err < 0)
1856 goto unlock;
1857
1858 if (changed)
1859 err = new_settings(hdev, sk);
1860
1861unlock:
1862 hci_dev_unlock(hdev);
1863 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001864}
1865
Marcel Holtmann1904a852015-01-11 13:50:44 -08001866static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867{
1868 struct cmd_lookup match = { NULL, hdev };
1869
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301870 hci_dev_lock(hdev);
1871
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001872 if (status) {
1873 u8 mgmt_err = mgmt_status(status);
1874
1875 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1876 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301877 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001878 }
1879
1880 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1881
1882 new_settings(hdev, match.sk);
1883
1884 if (match.sk)
1885 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001886
1887 /* Make sure the controller has a good default for
1888 * advertising data. Restrict the update to when LE
1889 * has actually been enabled. During power on, the
1890 * update in powered_update_hci will take care of it.
1891 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001892 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001893 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001894 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301895 if (ext_adv_capable(hdev)) {
1896 int err;
1897
1898 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1899 if (!err)
1900 __hci_req_update_scan_rsp_data(&req, 0x00);
1901 } else {
1902 __hci_req_update_adv_data(&req, 0x00);
1903 __hci_req_update_scan_rsp_data(&req, 0x00);
1904 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001905 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001906 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001907 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301908
1909unlock:
1910 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001911}
1912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914{
1915 struct mgmt_mode *cp = data;
1916 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001917 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001918 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001919 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001920 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001921
Marcel Holtmann181d6952020-05-06 09:57:47 +02001922 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001923
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001924 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1926 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001927
Johan Hedberga7e80f22013-01-09 16:05:19 +02001928 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001929 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1930 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001931
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001932 /* Bluetooth single mode LE only controllers or dual-mode
1933 * controllers configured as LE only devices, do not allow
1934 * switching LE off. These have either LE enabled explicitly
1935 * or BR/EDR has been previously switched off.
1936 *
1937 * When trying to enable an already enabled LE, then gracefully
1938 * send a positive response. Trying to disable it however will
1939 * result into rejection.
1940 */
1941 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1942 if (cp->val == 0x01)
1943 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1944
Johan Hedberga69e8372015-03-06 21:08:53 +02001945 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1946 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001947 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001948
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001949 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950
1951 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001952 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001953
Florian Grandel847818d2015-06-18 03:16:46 +02001954 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001955 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001956
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001957 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001958 bool changed = false;
1959
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001960 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001961 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 changed = true;
1963 }
1964
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001965 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001966 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001967 changed = true;
1968 }
1969
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1971 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001972 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973
1974 if (changed)
1975 err = new_settings(hdev, sk);
1976
Johan Hedberg1de028c2012-02-29 19:55:35 -08001977 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001978 }
1979
Johan Hedberg333ae952015-03-17 13:48:47 +02001980 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1981 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001982 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1983 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001984 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001985 }
1986
1987 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1988 if (!cmd) {
1989 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001990 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001991 }
1992
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001993 hci_req_init(&req, hdev);
1994
Johan Hedberg06199cf2012-02-22 16:37:11 +02001995 memset(&hci_cp, 0, sizeof(hci_cp));
1996
1997 if (val) {
1998 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001999 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002000 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002001 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002002 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05302003
2004 if (ext_adv_capable(hdev))
2005 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002006 }
2007
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002008 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2009 &hci_cp);
2010
2011 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302012 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002013 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002014
Johan Hedberg1de028c2012-02-29 19:55:35 -08002015unlock:
2016 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002017 return err;
2018}
2019
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002020/* This is a helper function to test for pending mgmt commands that can
2021 * cause CoD or EIR HCI commands. We can only allow one such pending
2022 * mgmt command at a time since otherwise we cannot easily track what
2023 * the current values are, will be, and based on that calculate if a new
2024 * HCI command needs to be sent and if yes with what value.
2025 */
2026static bool pending_eir_or_class(struct hci_dev *hdev)
2027{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002028 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002029
2030 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2031 switch (cmd->opcode) {
2032 case MGMT_OP_ADD_UUID:
2033 case MGMT_OP_REMOVE_UUID:
2034 case MGMT_OP_SET_DEV_CLASS:
2035 case MGMT_OP_SET_POWERED:
2036 return true;
2037 }
2038 }
2039
2040 return false;
2041}
2042
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002043static const u8 bluetooth_base_uuid[] = {
2044 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2045 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2046};
2047
2048static u8 get_uuid_size(const u8 *uuid)
2049{
2050 u32 val;
2051
2052 if (memcmp(uuid, bluetooth_base_uuid, 12))
2053 return 128;
2054
2055 val = get_unaligned_le32(&uuid[12]);
2056 if (val > 0xffff)
2057 return 32;
2058
2059 return 16;
2060}
2061
Johan Hedberg92da6092013-03-15 17:06:55 -05002062static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2063{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002064 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002065
2066 hci_dev_lock(hdev);
2067
Johan Hedberg333ae952015-03-17 13:48:47 +02002068 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002069 if (!cmd)
2070 goto unlock;
2071
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002072 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2073 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002074
2075 mgmt_pending_remove(cmd);
2076
2077unlock:
2078 hci_dev_unlock(hdev);
2079}
2080
Marcel Holtmann1904a852015-01-11 13:50:44 -08002081static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002082{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002083 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002084
2085 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2086}
2087
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002088static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002090 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002091 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002093 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094 int err;
2095
Marcel Holtmann181d6952020-05-06 09:57:47 +02002096 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002100 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002101 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2102 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002103 goto failed;
2104 }
2105
Andre Guedes92c4c202012-06-07 19:05:44 -03002106 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002107 if (!uuid) {
2108 err = -ENOMEM;
2109 goto failed;
2110 }
2111
2112 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002113 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002114 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002115
Johan Hedbergde66aa62013-01-27 00:31:27 +02002116 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117
Johan Hedberg890ea892013-03-15 17:06:52 -05002118 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002119
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002120 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002121 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002122
Johan Hedberg92da6092013-03-15 17:06:55 -05002123 err = hci_req_run(&req, add_uuid_complete);
2124 if (err < 0) {
2125 if (err != -ENODATA)
2126 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002127
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002128 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2129 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002130 goto failed;
2131 }
2132
2133 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002134 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002135 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002136 goto failed;
2137 }
2138
2139 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002140
2141failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002142 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143 return err;
2144}
2145
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146static bool enable_service_cache(struct hci_dev *hdev)
2147{
2148 if (!hdev_is_powered(hdev))
2149 return false;
2150
Marcel Holtmann238be782015-03-13 02:11:06 -07002151 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002152 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2153 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002154 return true;
2155 }
2156
2157 return false;
2158}
2159
Marcel Holtmann1904a852015-01-11 13:50:44 -08002160static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002161{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002162 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002163
2164 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2165}
2166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002167static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002168 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002169{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002170 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002171 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002172 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002173 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 -05002174 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002175 int err, found;
2176
Marcel Holtmann181d6952020-05-06 09:57:47 +02002177 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002179 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002180
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002181 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002182 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2183 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002184 goto unlock;
2185 }
2186
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002187 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002188 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002189
Johan Hedberg24b78d02012-02-23 23:24:30 +02002190 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002191 err = mgmt_cmd_complete(sk, hdev->id,
2192 MGMT_OP_REMOVE_UUID,
2193 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002194 goto unlock;
2195 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002196
Johan Hedberg9246a862012-02-23 21:33:16 +02002197 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002198 }
2199
2200 found = 0;
2201
Johan Hedberg056341c2013-01-27 00:31:30 +02002202 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002203 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2204 continue;
2205
2206 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002207 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002208 found++;
2209 }
2210
2211 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002212 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2213 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002214 goto unlock;
2215 }
2216
Johan Hedberg9246a862012-02-23 21:33:16 +02002217update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002218 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002219
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002220 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002221 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002222
Johan Hedberg92da6092013-03-15 17:06:55 -05002223 err = hci_req_run(&req, remove_uuid_complete);
2224 if (err < 0) {
2225 if (err != -ENODATA)
2226 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002227
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002228 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2229 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002230 goto unlock;
2231 }
2232
2233 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002234 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002235 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002236 goto unlock;
2237 }
2238
2239 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002240
2241unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002242 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002243 return err;
2244}
2245
Marcel Holtmann1904a852015-01-11 13:50:44 -08002246static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002247{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002248 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002249
2250 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2251}
2252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002254 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002257 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002258 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002259 int err;
2260
Marcel Holtmann181d6952020-05-06 09:57:47 +02002261 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002262
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002263 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002264 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2265 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002267 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002268
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002269 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002270 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2271 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002272 goto unlock;
2273 }
2274
2275 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002276 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2277 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002278 goto unlock;
2279 }
2280
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002281 hdev->major_class = cp->major;
2282 hdev->minor_class = cp->minor;
2283
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002284 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002285 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2286 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002287 goto unlock;
2288 }
2289
Johan Hedberg890ea892013-03-15 17:06:52 -05002290 hci_req_init(&req, hdev);
2291
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002292 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002293 hci_dev_unlock(hdev);
2294 cancel_delayed_work_sync(&hdev->service_cache);
2295 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002296 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002297 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002298
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002299 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002300
Johan Hedberg92da6092013-03-15 17:06:55 -05002301 err = hci_req_run(&req, set_class_complete);
2302 if (err < 0) {
2303 if (err != -ENODATA)
2304 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002305
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002306 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2307 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002308 goto unlock;
2309 }
2310
2311 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002312 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002313 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002314 goto unlock;
2315 }
2316
2317 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002318
Johan Hedbergb5235a62012-02-21 14:32:24 +02002319unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002320 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002321 return err;
2322}
2323
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002324static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002325 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002326{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002327 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002328 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2329 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002330 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002331 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002332 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333
Marcel Holtmann181d6952020-05-06 09:57:47 +02002334 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002335
2336 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002337 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2338 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002339
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002340 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002341 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002342 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2343 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002344 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2345 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002346 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002347
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002348 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002349 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002350 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2351 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002352 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002354 }
2355
Johan Hedberg4ae143012013-01-20 14:27:13 +02002356 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002357 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2358 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002359
Marcel Holtmann181d6952020-05-06 09:57:47 +02002360 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2361 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002362
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002363 for (i = 0; i < key_count; i++) {
2364 struct mgmt_link_key_info *key = &cp->keys[i];
2365
Marcel Holtmann8e991132014-01-10 02:07:25 -08002366 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002367 return mgmt_cmd_status(sk, hdev->id,
2368 MGMT_OP_LOAD_LINK_KEYS,
2369 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002370 }
2371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002372 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373
2374 hci_link_keys_clear(hdev);
2375
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002377 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002379 changed = hci_dev_test_and_clear_flag(hdev,
2380 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002381
2382 if (changed)
2383 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002384
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002385 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002386 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002387
Alain Michaud600a8742020-01-07 00:43:17 +00002388 if (hci_is_blocked_key(hdev,
2389 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2390 key->val)) {
2391 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2392 &key->addr.bdaddr);
2393 continue;
2394 }
2395
Johan Hedberg58e92932014-06-24 14:00:26 +03002396 /* Always ignore debug keys and require a new pairing if
2397 * the user wants to use them.
2398 */
2399 if (key->type == HCI_LK_DEBUG_COMBINATION)
2400 continue;
2401
Johan Hedberg7652ff62014-06-24 13:15:49 +03002402 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2403 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002404 }
2405
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002406 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002408 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002409
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002410 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002411}
2412
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002413static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002414 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002415{
2416 struct mgmt_ev_device_unpaired ev;
2417
2418 bacpy(&ev.addr.bdaddr, bdaddr);
2419 ev.addr.type = addr_type;
2420
2421 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002422 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002423}
2424
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002425static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002427{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002428 struct mgmt_cp_unpair_device *cp = data;
2429 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002430 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002431 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002432 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002433 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002434 int err;
2435
Johan Hedberga8a1d192011-11-10 15:54:38 +02002436 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002437 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2438 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002439
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002440 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002441 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_INVALID_PARAMS,
2443 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002444
Johan Hedberg118da702013-01-20 14:27:20 +02002445 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002446 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2447 MGMT_STATUS_INVALID_PARAMS,
2448 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002449
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002450 hci_dev_lock(hdev);
2451
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002452 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002453 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2454 MGMT_STATUS_NOT_POWERED, &rp,
2455 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002456 goto unlock;
2457 }
2458
Johan Hedberge0b2b272014-02-18 17:14:31 +02002459 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002460 /* If disconnection is requested, then look up the
2461 * connection. If the remote device is connected, it
2462 * will be later used to terminate the link.
2463 *
2464 * Setting it to NULL explicitly will cause no
2465 * termination of the link.
2466 */
2467 if (cp->disconnect)
2468 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2469 &cp->addr.bdaddr);
2470 else
2471 conn = NULL;
2472
Johan Hedberg124f6e32012-02-09 13:50:12 +02002473 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002474 if (err < 0) {
2475 err = mgmt_cmd_complete(sk, hdev->id,
2476 MGMT_OP_UNPAIR_DEVICE,
2477 MGMT_STATUS_NOT_PAIRED, &rp,
2478 sizeof(rp));
2479 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002480 }
2481
Johan Hedbergec182f02015-10-21 18:03:03 +03002482 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002483 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002484
Johan Hedbergec182f02015-10-21 18:03:03 +03002485 /* LE address type */
2486 addr_type = le_addr_type(cp->addr.type);
2487
Matias Karhumaacb28c302018-09-26 09:13:46 +03002488 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2489 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002490 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002491 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2492 MGMT_STATUS_NOT_PAIRED, &rp,
2493 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002494 goto unlock;
2495 }
2496
Johan Hedbergec182f02015-10-21 18:03:03 +03002497 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2498 if (!conn) {
2499 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2500 goto done;
2501 }
2502
Johan Hedbergc81d5552015-10-22 09:38:35 +03002503
Johan Hedbergec182f02015-10-21 18:03:03 +03002504 /* Defer clearing up the connection parameters until closing to
2505 * give a chance of keeping them if a repairing happens.
2506 */
2507 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2508
Johan Hedbergfc643612015-10-22 09:38:31 +03002509 /* Disable auto-connection parameters if present */
2510 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2511 if (params) {
2512 if (params->explicit_connect)
2513 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2514 else
2515 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2516 }
2517
Johan Hedbergec182f02015-10-21 18:03:03 +03002518 /* If disconnection is not requested, then clear the connection
2519 * variable so that the link is not terminated.
2520 */
2521 if (!cp->disconnect)
2522 conn = NULL;
2523
2524done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002525 /* If the connection variable is set, then termination of the
2526 * link is requested.
2527 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002528 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002529 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2530 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002531 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002532 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002533 }
2534
Johan Hedberg124f6e32012-02-09 13:50:12 +02002535 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002537 if (!cmd) {
2538 err = -ENOMEM;
2539 goto unlock;
2540 }
2541
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002542 cmd->cmd_complete = addr_cmd_complete;
2543
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002544 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002545 if (err < 0)
2546 mgmt_pending_remove(cmd);
2547
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002548unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002549 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002550 return err;
2551}
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002556 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002557 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002558 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002559 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002560 int err;
2561
Marcel Holtmann181d6952020-05-06 09:57:47 +02002562 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002563
Johan Hedberg06a63b12013-01-20 14:27:21 +02002564 memset(&rp, 0, sizeof(rp));
2565 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2566 rp.addr.type = cp->addr.type;
2567
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002568 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002569 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2570 MGMT_STATUS_INVALID_PARAMS,
2571 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002574
2575 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002576 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2577 MGMT_STATUS_NOT_POWERED, &rp,
2578 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002579 goto failed;
2580 }
2581
Johan Hedberg333ae952015-03-17 13:48:47 +02002582 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002583 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2584 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002585 goto failed;
2586 }
2587
Andre Guedes591f47f2012-04-24 21:02:49 -03002588 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002589 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2590 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002591 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002592 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2593 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002594
Vishal Agarwalf9607272012-06-13 05:32:43 +05302595 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002596 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2597 MGMT_STATUS_NOT_CONNECTED, &rp,
2598 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002599 goto failed;
2600 }
2601
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002602 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002603 if (!cmd) {
2604 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002605 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002606 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002607
Johan Hedbergf5818c22014-12-05 13:36:02 +02002608 cmd->cmd_complete = generic_cmd_complete;
2609
Johan Hedberge3f2f922014-08-18 20:33:33 +03002610 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002611 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002612 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002613
2614failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002615 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002616 return err;
2617}
2618
Andre Guedes57c14772012-04-24 21:02:50 -03002619static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002620{
2621 switch (link_type) {
2622 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002623 switch (addr_type) {
2624 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002625 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002626
Johan Hedberg48264f02011-11-09 13:58:58 +02002627 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002628 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002629 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002630 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002631
Johan Hedberg4c659c32011-11-07 23:13:39 +02002632 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002633 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002634 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002635 }
2636}
2637
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2639 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002641 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002642 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002643 int err;
2644 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002645
Marcel Holtmann181d6952020-05-06 09:57:47 +02002646 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002648 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002649
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002650 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002651 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2652 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002653 goto unlock;
2654 }
2655
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002656 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002657 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2658 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002659 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002660 }
2661
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002662 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002663 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002664 err = -ENOMEM;
2665 goto unlock;
2666 }
2667
Johan Hedberg2784eb42011-01-21 13:56:35 +02002668 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002669 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002670 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2671 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002672 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002673 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002674 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002675 continue;
2676 i++;
2677 }
2678
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002679 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002680
Johan Hedberg4c659c32011-11-07 23:13:39 +02002681 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002682 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002683 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002684
Johan Hedberga38528f2011-01-22 06:46:43 +02002685 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002686
2687unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002688 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002689 return err;
2690}
2691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002693 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002694{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002695 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002696 int err;
2697
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002698 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002700 if (!cmd)
2701 return -ENOMEM;
2702
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002703 cmd->cmd_complete = addr_cmd_complete;
2704
Johan Hedbergd8457692012-02-17 14:24:57 +02002705 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002707 if (err < 0)
2708 mgmt_pending_remove(cmd);
2709
2710 return err;
2711}
2712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002713static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002714 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002716 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002717 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002719 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720 int err;
2721
Marcel Holtmann181d6952020-05-06 09:57:47 +02002722 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002724 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002726 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2728 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002729 goto failed;
2730 }
2731
Johan Hedbergd8457692012-02-17 14:24:57 +02002732 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002733 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002734 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2735 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002736 goto failed;
2737 }
2738
2739 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002740 struct mgmt_cp_pin_code_neg_reply ncp;
2741
2742 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002743
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002744 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002746 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002747 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002748 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2749 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002750
2751 goto failed;
2752 }
2753
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002754 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002755 if (!cmd) {
2756 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002757 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002758 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002759
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002760 cmd->cmd_complete = addr_cmd_complete;
2761
Johan Hedbergd8457692012-02-17 14:24:57 +02002762 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002763 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002764 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002765
2766 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2767 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002768 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002769
2770failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002771 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002772 return err;
2773}
2774
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2776 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002777{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002779
Marcel Holtmann181d6952020-05-06 09:57:47 +02002780 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002781
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002782 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002783 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2784 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002785
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002786 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002787
2788 hdev->io_capability = cp->io_capability;
2789
Marcel Holtmann181d6952020-05-06 09:57:47 +02002790 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002792 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002793
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002794 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2795 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002796}
2797
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002798static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799{
2800 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002801 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002802
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002803 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002804 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2805 continue;
2806
Johan Hedberge9a416b2011-02-19 12:05:56 -03002807 if (cmd->user_data != conn)
2808 continue;
2809
2810 return cmd;
2811 }
2812
2813 return NULL;
2814}
2815
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002816static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002817{
2818 struct mgmt_rp_pair_device rp;
2819 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002820 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002821
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002822 bacpy(&rp.addr.bdaddr, &conn->dst);
2823 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002824
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002825 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2826 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002827
2828 /* So we don't get further callbacks for this connection */
2829 conn->connect_cfm_cb = NULL;
2830 conn->security_cfm_cb = NULL;
2831 conn->disconn_cfm_cb = NULL;
2832
David Herrmann76a68ba2013-04-06 20:28:37 +02002833 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002834
2835 /* The device is paired so there is no need to remove
2836 * its connection parameters anymore.
2837 */
2838 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002839
2840 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002841
2842 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843}
2844
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002845void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2846{
2847 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002848 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002849
2850 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002851 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002852 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002853 mgmt_pending_remove(cmd);
2854 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002855}
2856
Johan Hedberge9a416b2011-02-19 12:05:56 -03002857static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2858{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002859 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002860
2861 BT_DBG("status %u", status);
2862
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002863 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002864 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002865 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002866 return;
2867 }
2868
2869 cmd->cmd_complete(cmd, mgmt_status(status));
2870 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002871}
2872
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002873static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302874{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002875 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302876
2877 BT_DBG("status %u", status);
2878
2879 if (!status)
2880 return;
2881
2882 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002883 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302884 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002885 return;
2886 }
2887
2888 cmd->cmd_complete(cmd, mgmt_status(status));
2889 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302890}
2891
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002892static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002893 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002895 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002896 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002897 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002898 u8 sec_level, auth_type;
2899 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002900 int err;
2901
Marcel Holtmann181d6952020-05-06 09:57:47 +02002902 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002903
Szymon Jancf950a30e2013-01-18 12:48:07 +01002904 memset(&rp, 0, sizeof(rp));
2905 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2906 rp.addr.type = cp->addr.type;
2907
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002908 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002909 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2910 MGMT_STATUS_INVALID_PARAMS,
2911 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002912
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002913 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002914 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2915 MGMT_STATUS_INVALID_PARAMS,
2916 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002917
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002918 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002919
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002920 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002921 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2922 MGMT_STATUS_NOT_POWERED, &rp,
2923 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002924 goto unlock;
2925 }
2926
Johan Hedberg55e76b32015-03-10 22:34:40 +02002927 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2928 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2929 MGMT_STATUS_ALREADY_PAIRED, &rp,
2930 sizeof(rp));
2931 goto unlock;
2932 }
2933
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002934 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002935 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002936
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002937 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002938 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002939 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002940 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002941 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002942 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002943
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002944 /* When pairing a new device, it is expected to remember
2945 * this device for future connections. Adding the connection
2946 * parameter information ahead of time allows tracking
2947 * of the slave preferred values and will speed up any
2948 * further connection establishment.
2949 *
2950 * If connection parameters already exist, then they
2951 * will be kept and this function does nothing.
2952 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002953 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2954
2955 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2956 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002957
Manish Mandlik76b13992020-06-17 16:39:19 +02002958 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2959 sec_level, HCI_LE_CONN_TIMEOUT,
2960 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002961 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002962
Ville Tervo30e76272011-02-22 16:10:53 -03002963 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002964 int status;
2965
2966 if (PTR_ERR(conn) == -EBUSY)
2967 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002968 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2969 status = MGMT_STATUS_NOT_SUPPORTED;
2970 else if (PTR_ERR(conn) == -ECONNREFUSED)
2971 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002972 else
2973 status = MGMT_STATUS_CONNECT_FAILED;
2974
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002975 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2976 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002977 goto unlock;
2978 }
2979
2980 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002981 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002982 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2983 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002984 goto unlock;
2985 }
2986
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002987 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002988 if (!cmd) {
2989 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002990 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002991 goto unlock;
2992 }
2993
Johan Hedberg04ab2742014-12-05 13:36:04 +02002994 cmd->cmd_complete = pairing_complete;
2995
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002996 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002997 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002998 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002999 conn->security_cfm_cb = pairing_complete_cb;
3000 conn->disconn_cfm_cb = pairing_complete_cb;
3001 } else {
3002 conn->connect_cfm_cb = le_pairing_complete_cb;
3003 conn->security_cfm_cb = le_pairing_complete_cb;
3004 conn->disconn_cfm_cb = le_pairing_complete_cb;
3005 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003006
Johan Hedberge9a416b2011-02-19 12:05:56 -03003007 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003008 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003009
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003010 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003011 hci_conn_security(conn, sec_level, auth_type, true)) {
3012 cmd->cmd_complete(cmd, 0);
3013 mgmt_pending_remove(cmd);
3014 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003015
3016 err = 0;
3017
3018unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003019 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003020 return err;
3021}
3022
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3024 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003025{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003026 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003027 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003028 struct hci_conn *conn;
3029 int err;
3030
Marcel Holtmann181d6952020-05-06 09:57:47 +02003031 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003032
Johan Hedberg28424702012-02-02 04:02:29 +02003033 hci_dev_lock(hdev);
3034
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003035 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003036 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3037 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003038 goto unlock;
3039 }
3040
Johan Hedberg333ae952015-03-17 13:48:47 +02003041 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003042 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003043 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3044 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003045 goto unlock;
3046 }
3047
3048 conn = cmd->user_data;
3049
3050 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003051 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3052 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003053 goto unlock;
3054 }
3055
Johan Hedberga511b352014-12-11 21:45:45 +02003056 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3057 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003058
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003059 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3060 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003061
3062 /* Since user doesn't want to proceed with the connection, abort any
3063 * ongoing pairing and then terminate the link if it was created
3064 * because of the pair device action.
3065 */
3066 if (addr->type == BDADDR_BREDR)
3067 hci_remove_link_key(hdev, &addr->bdaddr);
3068 else
3069 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3070 le_addr_type(addr->type));
3071
3072 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3073 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3074
Johan Hedberg28424702012-02-02 04:02:29 +02003075unlock:
3076 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003077 return err;
3078}
3079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003080static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003081 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003083{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003084 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003085 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003086 int err;
3087
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003088 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003089
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003090 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003091 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3092 MGMT_STATUS_NOT_POWERED, addr,
3093 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003094 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003095 }
3096
Johan Hedberg1707c602013-03-15 17:07:15 -05003097 if (addr->type == BDADDR_BREDR)
3098 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003099 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003100 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3101 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003102
Johan Hedberg272d90d2012-02-09 15:26:12 +02003103 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003104 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3105 MGMT_STATUS_NOT_CONNECTED, addr,
3106 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003107 goto done;
3108 }
3109
Johan Hedberg1707c602013-03-15 17:07:15 -05003110 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003111 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003112 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003113 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3114 MGMT_STATUS_SUCCESS, addr,
3115 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003116 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003117 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3118 MGMT_STATUS_FAILED, addr,
3119 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003120
Brian Gix47c15e22011-11-16 13:53:14 -08003121 goto done;
3122 }
3123
Johan Hedberg1707c602013-03-15 17:07:15 -05003124 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003125 if (!cmd) {
3126 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003127 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003128 }
3129
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003130 cmd->cmd_complete = addr_cmd_complete;
3131
Brian Gix0df4c182011-11-16 13:53:13 -08003132 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003133 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3134 struct hci_cp_user_passkey_reply cp;
3135
Johan Hedberg1707c602013-03-15 17:07:15 -05003136 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003137 cp.passkey = passkey;
3138 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3139 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003140 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3141 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003142
Johan Hedberga664b5b2011-02-19 12:06:02 -03003143 if (err < 0)
3144 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003145
Brian Gix0df4c182011-11-16 13:53:13 -08003146done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003147 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003148 return err;
3149}
3150
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303151static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3152 void *data, u16 len)
3153{
3154 struct mgmt_cp_pin_code_neg_reply *cp = data;
3155
Marcel Holtmann181d6952020-05-06 09:57:47 +02003156 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303157
Johan Hedberg1707c602013-03-15 17:07:15 -05003158 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303159 MGMT_OP_PIN_CODE_NEG_REPLY,
3160 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3161}
3162
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003163static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3164 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003165{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003166 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003167
Marcel Holtmann181d6952020-05-06 09:57:47 +02003168 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003169
3170 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003171 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3172 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003173
Johan Hedberg1707c602013-03-15 17:07:15 -05003174 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 MGMT_OP_USER_CONFIRM_REPLY,
3176 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003177}
3178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003179static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003181{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003182 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003183
Marcel Holtmann181d6952020-05-06 09:57:47 +02003184 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003185
Johan Hedberg1707c602013-03-15 17:07:15 -05003186 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003187 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3188 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003189}
3190
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3192 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003193{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003194 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003195
Marcel Holtmann181d6952020-05-06 09:57:47 +02003196 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003197
Johan Hedberg1707c602013-03-15 17:07:15 -05003198 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003199 MGMT_OP_USER_PASSKEY_REPLY,
3200 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003201}
3202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003203static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003204 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003206 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003207
Marcel Holtmann181d6952020-05-06 09:57:47 +02003208 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003209
Johan Hedberg1707c602013-03-15 17:07:15 -05003210 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003211 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3212 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003213}
3214
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003215static void adv_expire(struct hci_dev *hdev, u32 flags)
3216{
3217 struct adv_info *adv_instance;
3218 struct hci_request req;
3219 int err;
3220
3221 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3222 if (!adv_instance)
3223 return;
3224
3225 /* stop if current instance doesn't need to be changed */
3226 if (!(adv_instance->flags & flags))
3227 return;
3228
3229 cancel_adv_timeout(hdev);
3230
3231 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3232 if (!adv_instance)
3233 return;
3234
3235 hci_req_init(&req, hdev);
3236 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3237 true);
3238 if (err)
3239 return;
3240
3241 hci_req_run(&req, NULL);
3242}
3243
Marcel Holtmann1904a852015-01-11 13:50:44 -08003244static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003245{
3246 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003247 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003248
Marcel Holtmann181d6952020-05-06 09:57:47 +02003249 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003250
3251 hci_dev_lock(hdev);
3252
Johan Hedberg333ae952015-03-17 13:48:47 +02003253 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003254 if (!cmd)
3255 goto unlock;
3256
3257 cp = cmd->param;
3258
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003259 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003260 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3261 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003262 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003263 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3264 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003265
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003266 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3267 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3268 }
3269
Johan Hedberg13928972013-03-15 17:07:00 -05003270 mgmt_pending_remove(cmd);
3271
3272unlock:
3273 hci_dev_unlock(hdev);
3274}
3275
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003276static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003277 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003278{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003279 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003280 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003281 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003282 int err;
3283
Marcel Holtmann181d6952020-05-06 09:57:47 +02003284 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003285
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003286 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003287
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003288 /* If the old values are the same as the new ones just return a
3289 * direct command complete event.
3290 */
3291 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3292 !memcmp(hdev->short_name, cp->short_name,
3293 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003294 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3295 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003296 goto failed;
3297 }
3298
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003299 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003300
Johan Hedbergb5235a62012-02-21 14:32:24 +02003301 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003302 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003303
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003304 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3305 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003306 if (err < 0)
3307 goto failed;
3308
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003309 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3310 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003311 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003312
Johan Hedbergb5235a62012-02-21 14:32:24 +02003313 goto failed;
3314 }
3315
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003316 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003317 if (!cmd) {
3318 err = -ENOMEM;
3319 goto failed;
3320 }
3321
Johan Hedberg13928972013-03-15 17:07:00 -05003322 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3323
Johan Hedberg890ea892013-03-15 17:06:52 -05003324 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003325
3326 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003327 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003328 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003329 }
3330
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003331 /* The name is stored in the scan response data and so
3332 * no need to udpate the advertising data here.
3333 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003334 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003335 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003336
Johan Hedberg13928972013-03-15 17:07:00 -05003337 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003338 if (err < 0)
3339 mgmt_pending_remove(cmd);
3340
3341failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003342 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003343 return err;
3344}
3345
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003346static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3347 u16 len)
3348{
3349 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003350 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003351 int err;
3352
Marcel Holtmann181d6952020-05-06 09:57:47 +02003353 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003354
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003355 if (!lmp_le_capable(hdev))
3356 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3357 MGMT_STATUS_NOT_SUPPORTED);
3358
Alain Michaud6613bab2020-01-22 19:47:44 +00003359 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003360
3361 hci_dev_lock(hdev);
3362
Alain Michaud6613bab2020-01-22 19:47:44 +00003363 if (hdev->appearance != appearance) {
3364 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003365
3366 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3367 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003368
3369 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003370 }
3371
3372 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3373 0);
3374
3375 hci_dev_unlock(hdev);
3376
3377 return err;
3378}
3379
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303380static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3381 void *data, u16 len)
3382{
3383 struct mgmt_rp_get_phy_confguration rp;
3384
Marcel Holtmann181d6952020-05-06 09:57:47 +02003385 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303386
3387 hci_dev_lock(hdev);
3388
3389 memset(&rp, 0, sizeof(rp));
3390
3391 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3392 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3393 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3394
3395 hci_dev_unlock(hdev);
3396
3397 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3398 &rp, sizeof(rp));
3399}
3400
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303401int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3402{
3403 struct mgmt_ev_phy_configuration_changed ev;
3404
3405 memset(&ev, 0, sizeof(ev));
3406
3407 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3408
3409 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3410 sizeof(ev), skip);
3411}
3412
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303413static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3414 u16 opcode, struct sk_buff *skb)
3415{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303416 struct mgmt_pending_cmd *cmd;
3417
Marcel Holtmann181d6952020-05-06 09:57:47 +02003418 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303419
3420 hci_dev_lock(hdev);
3421
3422 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3423 if (!cmd)
3424 goto unlock;
3425
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303426 if (status) {
3427 mgmt_cmd_status(cmd->sk, hdev->id,
3428 MGMT_OP_SET_PHY_CONFIGURATION,
3429 mgmt_status(status));
3430 } else {
3431 mgmt_cmd_complete(cmd->sk, hdev->id,
3432 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3433 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303434
3435 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303436 }
3437
3438 mgmt_pending_remove(cmd);
3439
3440unlock:
3441 hci_dev_unlock(hdev);
3442}
3443
3444static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3445 void *data, u16 len)
3446{
3447 struct mgmt_cp_set_phy_confguration *cp = data;
3448 struct hci_cp_le_set_default_phy cp_phy;
3449 struct mgmt_pending_cmd *cmd;
3450 struct hci_request req;
3451 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3452 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303453 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303454 int err;
3455
Marcel Holtmann181d6952020-05-06 09:57:47 +02003456 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303457
3458 configurable_phys = get_configurable_phys(hdev);
3459 supported_phys = get_supported_phys(hdev);
3460 selected_phys = __le32_to_cpu(cp->selected_phys);
3461
3462 if (selected_phys & ~supported_phys)
3463 return mgmt_cmd_status(sk, hdev->id,
3464 MGMT_OP_SET_PHY_CONFIGURATION,
3465 MGMT_STATUS_INVALID_PARAMS);
3466
3467 unconfigure_phys = supported_phys & ~configurable_phys;
3468
3469 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3470 return mgmt_cmd_status(sk, hdev->id,
3471 MGMT_OP_SET_PHY_CONFIGURATION,
3472 MGMT_STATUS_INVALID_PARAMS);
3473
3474 if (selected_phys == get_selected_phys(hdev))
3475 return mgmt_cmd_complete(sk, hdev->id,
3476 MGMT_OP_SET_PHY_CONFIGURATION,
3477 0, NULL, 0);
3478
3479 hci_dev_lock(hdev);
3480
3481 if (!hdev_is_powered(hdev)) {
3482 err = mgmt_cmd_status(sk, hdev->id,
3483 MGMT_OP_SET_PHY_CONFIGURATION,
3484 MGMT_STATUS_REJECTED);
3485 goto unlock;
3486 }
3487
3488 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3489 err = mgmt_cmd_status(sk, hdev->id,
3490 MGMT_OP_SET_PHY_CONFIGURATION,
3491 MGMT_STATUS_BUSY);
3492 goto unlock;
3493 }
3494
3495 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3496 pkt_type |= (HCI_DH3 | HCI_DM3);
3497 else
3498 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3499
3500 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3501 pkt_type |= (HCI_DH5 | HCI_DM5);
3502 else
3503 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3504
3505 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3506 pkt_type &= ~HCI_2DH1;
3507 else
3508 pkt_type |= HCI_2DH1;
3509
3510 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3511 pkt_type &= ~HCI_2DH3;
3512 else
3513 pkt_type |= HCI_2DH3;
3514
3515 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3516 pkt_type &= ~HCI_2DH5;
3517 else
3518 pkt_type |= HCI_2DH5;
3519
3520 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3521 pkt_type &= ~HCI_3DH1;
3522 else
3523 pkt_type |= HCI_3DH1;
3524
3525 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3526 pkt_type &= ~HCI_3DH3;
3527 else
3528 pkt_type |= HCI_3DH3;
3529
3530 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3531 pkt_type &= ~HCI_3DH5;
3532 else
3533 pkt_type |= HCI_3DH5;
3534
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303535 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303536 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303537 changed = true;
3538 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303539
3540 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3541 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303542 if (changed)
3543 mgmt_phy_configuration_changed(hdev, sk);
3544
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303545 err = mgmt_cmd_complete(sk, hdev->id,
3546 MGMT_OP_SET_PHY_CONFIGURATION,
3547 0, NULL, 0);
3548
3549 goto unlock;
3550 }
3551
3552 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3553 len);
3554 if (!cmd) {
3555 err = -ENOMEM;
3556 goto unlock;
3557 }
3558
3559 hci_req_init(&req, hdev);
3560
3561 memset(&cp_phy, 0, sizeof(cp_phy));
3562
3563 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3564 cp_phy.all_phys |= 0x01;
3565
3566 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3567 cp_phy.all_phys |= 0x02;
3568
3569 if (selected_phys & MGMT_PHY_LE_1M_TX)
3570 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3571
3572 if (selected_phys & MGMT_PHY_LE_2M_TX)
3573 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3574
3575 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3576 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3577
3578 if (selected_phys & MGMT_PHY_LE_1M_RX)
3579 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3580
3581 if (selected_phys & MGMT_PHY_LE_2M_RX)
3582 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3583
3584 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3585 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3586
3587 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3588
3589 err = hci_req_run_skb(&req, set_default_phy_complete);
3590 if (err < 0)
3591 mgmt_pending_remove(cmd);
3592
3593unlock:
3594 hci_dev_unlock(hdev);
3595
3596 return err;
3597}
3598
Alain Michaud600a8742020-01-07 00:43:17 +00003599static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3600 u16 len)
3601{
3602 int err = MGMT_STATUS_SUCCESS;
3603 struct mgmt_cp_set_blocked_keys *keys = data;
3604 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3605 sizeof(struct mgmt_blocked_key_info));
3606 u16 key_count, expected_len;
3607 int i;
3608
Marcel Holtmann181d6952020-05-06 09:57:47 +02003609 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003610
3611 key_count = __le16_to_cpu(keys->key_count);
3612 if (key_count > max_key_count) {
3613 bt_dev_err(hdev, "too big key_count value %u", key_count);
3614 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3615 MGMT_STATUS_INVALID_PARAMS);
3616 }
3617
3618 expected_len = struct_size(keys, keys, key_count);
3619 if (expected_len != len) {
3620 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3621 expected_len, len);
3622 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3623 MGMT_STATUS_INVALID_PARAMS);
3624 }
3625
3626 hci_dev_lock(hdev);
3627
3628 hci_blocked_keys_clear(hdev);
3629
3630 for (i = 0; i < keys->key_count; ++i) {
3631 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3632
3633 if (!b) {
3634 err = MGMT_STATUS_NO_RESOURCES;
3635 break;
3636 }
3637
3638 b->type = keys->keys[i].type;
3639 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3640 list_add_rcu(&b->list, &hdev->blocked_keys);
3641 }
3642 hci_dev_unlock(hdev);
3643
3644 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3645 err, NULL, 0);
3646}
3647
Alain Michaud00bce3f2020-03-05 16:14:59 +00003648static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3649 void *data, u16 len)
3650{
3651 struct mgmt_mode *cp = data;
3652 int err;
3653 bool changed = false;
3654
Marcel Holtmann181d6952020-05-06 09:57:47 +02003655 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003656
3657 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3658 return mgmt_cmd_status(sk, hdev->id,
3659 MGMT_OP_SET_WIDEBAND_SPEECH,
3660 MGMT_STATUS_NOT_SUPPORTED);
3661
3662 if (cp->val != 0x00 && cp->val != 0x01)
3663 return mgmt_cmd_status(sk, hdev->id,
3664 MGMT_OP_SET_WIDEBAND_SPEECH,
3665 MGMT_STATUS_INVALID_PARAMS);
3666
3667 hci_dev_lock(hdev);
3668
3669 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3670 err = mgmt_cmd_status(sk, hdev->id,
3671 MGMT_OP_SET_WIDEBAND_SPEECH,
3672 MGMT_STATUS_BUSY);
3673 goto unlock;
3674 }
3675
3676 if (hdev_is_powered(hdev) &&
3677 !!cp->val != hci_dev_test_flag(hdev,
3678 HCI_WIDEBAND_SPEECH_ENABLED)) {
3679 err = mgmt_cmd_status(sk, hdev->id,
3680 MGMT_OP_SET_WIDEBAND_SPEECH,
3681 MGMT_STATUS_REJECTED);
3682 goto unlock;
3683 }
3684
3685 if (cp->val)
3686 changed = !hci_dev_test_and_set_flag(hdev,
3687 HCI_WIDEBAND_SPEECH_ENABLED);
3688 else
3689 changed = hci_dev_test_and_clear_flag(hdev,
3690 HCI_WIDEBAND_SPEECH_ENABLED);
3691
3692 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3693 if (err < 0)
3694 goto unlock;
3695
3696 if (changed)
3697 err = new_settings(hdev, sk);
3698
3699unlock:
3700 hci_dev_unlock(hdev);
3701 return err;
3702}
3703
Marcel Holtmannbc292252020-04-03 21:44:05 +02003704static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3705 void *data, u16 data_len)
3706{
3707 char buf[16];
3708 struct mgmt_rp_read_security_info *rp = (void *)buf;
3709 u16 sec_len = 0;
3710 u8 flags = 0;
3711
3712 bt_dev_dbg(hdev, "sock %p", sk);
3713
3714 memset(&buf, 0, sizeof(buf));
3715
3716 hci_dev_lock(hdev);
3717
3718 /* When the Read Simple Pairing Options command is supported, then
3719 * the remote public key validation is supported.
3720 */
3721 if (hdev->commands[41] & 0x08)
3722 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3723
3724 flags |= 0x02; /* Remote public key validation (LE) */
3725
3726 /* When the Read Encryption Key Size command is supported, then the
3727 * encryption key size is enforced.
3728 */
3729 if (hdev->commands[20] & 0x10)
3730 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3731
3732 flags |= 0x08; /* Encryption key size enforcement (LE) */
3733
3734 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3735
3736 /* When the Read Simple Pairing Options command is supported, then
3737 * also max encryption key size information is provided.
3738 */
3739 if (hdev->commands[41] & 0x08)
3740 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3741 hdev->max_enc_key_size);
3742
3743 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3744
3745 rp->sec_len = cpu_to_le16(sec_len);
3746
3747 hci_dev_unlock(hdev);
3748
3749 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3750 rp, sizeof(*rp) + sec_len);
3751}
3752
Marcel Holtmanne625e502020-05-06 09:57:52 +02003753#ifdef CONFIG_BT_FEATURE_DEBUG
3754/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3755static const u8 debug_uuid[16] = {
3756 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3757 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3758};
3759#endif
3760
Alain Michaud15d8ce02020-07-07 17:46:06 +02003761/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3762static const u8 simult_central_periph_uuid[16] = {
3763 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3764 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3765};
3766
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303767/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3768static const u8 rpa_resolution_uuid[16] = {
3769 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3770 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3771};
3772
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003773static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3774 void *data, u16 data_len)
3775{
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303776 char buf[62]; /* Enough space for 3 features */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003777 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3778 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003779 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003780
3781 bt_dev_dbg(hdev, "sock %p", sk);
3782
3783 memset(&buf, 0, sizeof(buf));
3784
Marcel Holtmanne625e502020-05-06 09:57:52 +02003785#ifdef CONFIG_BT_FEATURE_DEBUG
3786 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003787 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003788
3789 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3790 rp->features[idx].flags = cpu_to_le32(flags);
3791 idx++;
3792 }
3793#endif
3794
Alain Michaud15d8ce02020-07-07 17:46:06 +02003795 if (hdev) {
3796 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3797 (hdev->le_states[4] & 0x08) && /* Central */
3798 (hdev->le_states[4] & 0x40) && /* Peripheral */
3799 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3800 flags = BIT(0);
3801 else
3802 flags = 0;
3803
3804 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3805 rp->features[idx].flags = cpu_to_le32(flags);
3806 idx++;
3807 }
3808
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303809 if (hdev && use_ll_privacy(hdev)) {
3810 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3811 flags = BIT(0) | BIT(1);
3812 else
3813 flags = BIT(1);
3814
3815 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3816 rp->features[idx].flags = cpu_to_le32(flags);
3817 idx++;
3818 }
3819
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003820 rp->feature_count = cpu_to_le16(idx);
3821
3822 /* After reading the experimental features information, enable
3823 * the events to update client on any future change.
3824 */
3825 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3826
3827 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3828 MGMT_OP_READ_EXP_FEATURES_INFO,
3829 0, rp, sizeof(*rp) + (20 * idx));
3830}
3831
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303832static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3833 struct sock *skip)
3834{
3835 struct mgmt_ev_exp_feature_changed ev;
3836
3837 memset(&ev, 0, sizeof(ev));
3838 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3839 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3840
3841 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3842 &ev, sizeof(ev),
3843 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3844
3845}
3846
Marcel Holtmanne625e502020-05-06 09:57:52 +02003847#ifdef CONFIG_BT_FEATURE_DEBUG
3848static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3849{
3850 struct mgmt_ev_exp_feature_changed ev;
3851
3852 memset(&ev, 0, sizeof(ev));
3853 memcpy(ev.uuid, debug_uuid, 16);
3854 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3855
3856 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3857 &ev, sizeof(ev),
3858 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3859}
3860#endif
3861
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003862static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3863 void *data, u16 data_len)
3864{
3865 struct mgmt_cp_set_exp_feature *cp = data;
3866 struct mgmt_rp_set_exp_feature rp;
3867
3868 bt_dev_dbg(hdev, "sock %p", sk);
3869
3870 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3871 memset(rp.uuid, 0, 16);
3872 rp.flags = cpu_to_le32(0);
3873
Marcel Holtmanne625e502020-05-06 09:57:52 +02003874#ifdef CONFIG_BT_FEATURE_DEBUG
3875 if (!hdev) {
3876 bool changed = bt_dbg_get();
3877
3878 bt_dbg_set(false);
3879
3880 if (changed)
3881 exp_debug_feature_changed(false, sk);
3882 }
3883#endif
3884
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303885 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3886 bool changed = hci_dev_test_flag(hdev,
3887 HCI_ENABLE_LL_PRIVACY);
3888
3889 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3890
3891 if (changed)
3892 exp_ll_privacy_feature_changed(false, hdev, sk);
3893 }
3894
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003895 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3896
3897 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3898 MGMT_OP_SET_EXP_FEATURE, 0,
3899 &rp, sizeof(rp));
3900 }
3901
Marcel Holtmanne625e502020-05-06 09:57:52 +02003902#ifdef CONFIG_BT_FEATURE_DEBUG
3903 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3904 bool val, changed;
3905 int err;
3906
3907 /* Command requires to use the non-controller index */
3908 if (hdev)
3909 return mgmt_cmd_status(sk, hdev->id,
3910 MGMT_OP_SET_EXP_FEATURE,
3911 MGMT_STATUS_INVALID_INDEX);
3912
3913 /* Parameters are limited to a single octet */
3914 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3915 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3916 MGMT_OP_SET_EXP_FEATURE,
3917 MGMT_STATUS_INVALID_PARAMS);
3918
3919 /* Only boolean on/off is supported */
3920 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3921 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3922 MGMT_OP_SET_EXP_FEATURE,
3923 MGMT_STATUS_INVALID_PARAMS);
3924
3925 val = !!cp->param[0];
3926 changed = val ? !bt_dbg_get() : bt_dbg_get();
3927 bt_dbg_set(val);
3928
3929 memcpy(rp.uuid, debug_uuid, 16);
3930 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3931
3932 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3933
3934 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3935 MGMT_OP_SET_EXP_FEATURE, 0,
3936 &rp, sizeof(rp));
3937
3938 if (changed)
3939 exp_debug_feature_changed(val, sk);
3940
3941 return err;
3942 }
3943#endif
3944
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303945 if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
3946 bool val, changed;
3947 int err;
3948 u32 flags;
3949
3950 /* Command requires to use the controller index */
3951 if (!hdev)
3952 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3953 MGMT_OP_SET_EXP_FEATURE,
3954 MGMT_STATUS_INVALID_INDEX);
3955
3956 /* Changes can only be made when controller is powered down */
3957 if (hdev_is_powered(hdev))
3958 return mgmt_cmd_status(sk, hdev->id,
3959 MGMT_OP_SET_EXP_FEATURE,
3960 MGMT_STATUS_NOT_POWERED);
3961
3962 /* Parameters are limited to a single octet */
3963 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3964 return mgmt_cmd_status(sk, hdev->id,
3965 MGMT_OP_SET_EXP_FEATURE,
3966 MGMT_STATUS_INVALID_PARAMS);
3967
3968 /* Only boolean on/off is supported */
3969 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3970 return mgmt_cmd_status(sk, hdev->id,
3971 MGMT_OP_SET_EXP_FEATURE,
3972 MGMT_STATUS_INVALID_PARAMS);
3973
3974 val = !!cp->param[0];
3975
3976 if (val) {
3977 changed = !hci_dev_test_flag(hdev,
3978 HCI_ENABLE_LL_PRIVACY);
3979 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3980 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
3981
3982 /* Enable LL privacy + supported settings changed */
3983 flags = BIT(0) | BIT(1);
3984 } else {
3985 changed = hci_dev_test_flag(hdev,
3986 HCI_ENABLE_LL_PRIVACY);
3987 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3988
3989 /* Disable LL privacy + supported settings changed */
3990 flags = BIT(1);
3991 }
3992
3993 memcpy(rp.uuid, rpa_resolution_uuid, 16);
3994 rp.flags = cpu_to_le32(flags);
3995
3996 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3997
3998 err = mgmt_cmd_complete(sk, hdev->id,
3999 MGMT_OP_SET_EXP_FEATURE, 0,
4000 &rp, sizeof(rp));
4001
4002 if (changed)
4003 exp_ll_privacy_feature_changed(val, hdev, sk);
4004
4005 return err;
4006 }
4007
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004008 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4009 MGMT_OP_SET_EXP_FEATURE,
4010 MGMT_STATUS_NOT_SUPPORTED);
4011}
4012
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004013#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4014
4015static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4016 u16 data_len)
4017{
4018 struct mgmt_cp_get_device_flags *cp = data;
4019 struct mgmt_rp_get_device_flags rp;
4020 struct bdaddr_list_with_flags *br_params;
4021 struct hci_conn_params *params;
4022 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4023 u32 current_flags = 0;
4024 u8 status = MGMT_STATUS_INVALID_PARAMS;
4025
4026 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4027 &cp->addr.bdaddr, cp->addr.type);
4028
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004029 hci_dev_lock(hdev);
4030
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004031 if (cp->addr.type == BDADDR_BREDR) {
4032 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4033 &cp->addr.bdaddr,
4034 cp->addr.type);
4035 if (!br_params)
4036 goto done;
4037
4038 current_flags = br_params->current_flags;
4039 } else {
4040 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4041 le_addr_type(cp->addr.type));
4042
4043 if (!params)
4044 goto done;
4045
4046 current_flags = params->current_flags;
4047 }
4048
4049 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4050 rp.addr.type = cp->addr.type;
4051 rp.supported_flags = cpu_to_le32(supported_flags);
4052 rp.current_flags = cpu_to_le32(current_flags);
4053
4054 status = MGMT_STATUS_SUCCESS;
4055
4056done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004057 hci_dev_unlock(hdev);
4058
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004059 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4060 &rp, sizeof(rp));
4061}
4062
4063static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4064 bdaddr_t *bdaddr, u8 bdaddr_type,
4065 u32 supported_flags, u32 current_flags)
4066{
4067 struct mgmt_ev_device_flags_changed ev;
4068
4069 bacpy(&ev.addr.bdaddr, bdaddr);
4070 ev.addr.type = bdaddr_type;
4071 ev.supported_flags = cpu_to_le32(supported_flags);
4072 ev.current_flags = cpu_to_le32(current_flags);
4073
4074 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4075}
4076
4077static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4078 u16 len)
4079{
4080 struct mgmt_cp_set_device_flags *cp = data;
4081 struct bdaddr_list_with_flags *br_params;
4082 struct hci_conn_params *params;
4083 u8 status = MGMT_STATUS_INVALID_PARAMS;
4084 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4085 u32 current_flags = __le32_to_cpu(cp->current_flags);
4086
4087 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4088 &cp->addr.bdaddr, cp->addr.type,
4089 __le32_to_cpu(current_flags));
4090
4091 if ((supported_flags | current_flags) != supported_flags) {
4092 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4093 current_flags, supported_flags);
4094 goto done;
4095 }
4096
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004097 hci_dev_lock(hdev);
4098
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004099 if (cp->addr.type == BDADDR_BREDR) {
4100 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4101 &cp->addr.bdaddr,
4102 cp->addr.type);
4103
4104 if (br_params) {
4105 br_params->current_flags = current_flags;
4106 status = MGMT_STATUS_SUCCESS;
4107 } else {
4108 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4109 &cp->addr.bdaddr, cp->addr.type);
4110 }
4111 } else {
4112 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4113 le_addr_type(cp->addr.type));
4114 if (params) {
4115 params->current_flags = current_flags;
4116 status = MGMT_STATUS_SUCCESS;
4117 } else {
4118 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4119 &cp->addr.bdaddr,
4120 le_addr_type(cp->addr.type));
4121 }
4122 }
4123
4124done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004125 hci_dev_unlock(hdev);
4126
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004127 if (status == MGMT_STATUS_SUCCESS)
4128 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4129 supported_flags, current_flags);
4130
4131 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4132 &cp->addr, sizeof(cp->addr));
4133}
4134
Miao-chen Choub52729f2020-06-17 16:39:16 +02004135static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4136 u16 handle)
4137{
4138 struct mgmt_ev_adv_monitor_added ev;
4139
4140 ev.monitor_handle = cpu_to_le16(handle);
4141
4142 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4143}
4144
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004145static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
4146 u16 handle)
4147{
4148 struct mgmt_ev_adv_monitor_added ev;
4149
4150 ev.monitor_handle = cpu_to_le16(handle);
4151
4152 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
4153}
4154
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004155static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4156 void *data, u16 len)
4157{
4158 struct adv_monitor *monitor = NULL;
4159 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
4160 int handle;
4161 size_t rp_size = 0;
4162 __u32 supported = 0;
4163 __u16 num_handles = 0;
4164 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4165
4166 BT_DBG("request for %s", hdev->name);
4167
4168 hci_dev_lock(hdev);
4169
4170 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
4171 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4172
4173 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
4174 handles[num_handles++] = monitor->handle;
4175 }
4176
4177 hci_dev_unlock(hdev);
4178
4179 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4180 rp = kmalloc(rp_size, GFP_KERNEL);
4181 if (!rp)
4182 return -ENOMEM;
4183
4184 /* Once controller-based monitoring is in place, the enabled_features
4185 * should reflect the use.
4186 */
4187 rp->supported_features = cpu_to_le32(supported);
4188 rp->enabled_features = 0;
4189 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4190 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4191 rp->num_handles = cpu_to_le16(num_handles);
4192 if (num_handles)
4193 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4194
4195 return mgmt_cmd_complete(sk, hdev->id,
4196 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4197 MGMT_STATUS_SUCCESS, rp, rp_size);
4198}
4199
Miao-chen Choub1395532020-06-17 16:39:14 +02004200static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4201 void *data, u16 len)
4202{
4203 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4204 struct mgmt_rp_add_adv_patterns_monitor rp;
4205 struct adv_monitor *m = NULL;
4206 struct adv_pattern *p = NULL;
Miao-chen Choub52729f2020-06-17 16:39:16 +02004207 unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
Miao-chen Choub1395532020-06-17 16:39:14 +02004208 __u8 cp_ofst = 0, cp_len = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004209 int err, i;
4210
4211 BT_DBG("request for %s", hdev->name);
4212
4213 if (len <= sizeof(*cp) || cp->pattern_count == 0) {
4214 err = mgmt_cmd_status(sk, hdev->id,
4215 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4216 MGMT_STATUS_INVALID_PARAMS);
4217 goto failed;
4218 }
4219
4220 m = kmalloc(sizeof(*m), GFP_KERNEL);
4221 if (!m) {
4222 err = -ENOMEM;
4223 goto failed;
4224 }
4225
4226 INIT_LIST_HEAD(&m->patterns);
4227 m->active = false;
4228
4229 for (i = 0; i < cp->pattern_count; i++) {
4230 if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
4231 err = mgmt_cmd_status(sk, hdev->id,
4232 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4233 MGMT_STATUS_INVALID_PARAMS);
4234 goto failed;
4235 }
4236
4237 cp_ofst = cp->patterns[i].offset;
4238 cp_len = cp->patterns[i].length;
4239 if (cp_ofst >= HCI_MAX_AD_LENGTH ||
4240 cp_len > HCI_MAX_AD_LENGTH ||
4241 (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
4242 err = mgmt_cmd_status(sk, hdev->id,
4243 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4244 MGMT_STATUS_INVALID_PARAMS);
4245 goto failed;
4246 }
4247
4248 p = kmalloc(sizeof(*p), GFP_KERNEL);
4249 if (!p) {
4250 err = -ENOMEM;
4251 goto failed;
4252 }
4253
4254 p->ad_type = cp->patterns[i].ad_type;
4255 p->offset = cp->patterns[i].offset;
4256 p->length = cp->patterns[i].length;
4257 memcpy(p->value, cp->patterns[i].value, p->length);
4258
4259 INIT_LIST_HEAD(&p->list);
4260 list_add(&p->list, &m->patterns);
4261 }
4262
4263 if (mp_cnt != cp->pattern_count) {
4264 err = mgmt_cmd_status(sk, hdev->id,
4265 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4266 MGMT_STATUS_INVALID_PARAMS);
4267 goto failed;
4268 }
4269
4270 hci_dev_lock(hdev);
4271
Miao-chen Choub52729f2020-06-17 16:39:16 +02004272 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4273
Miao-chen Choub1395532020-06-17 16:39:14 +02004274 err = hci_add_adv_monitor(hdev, m);
4275 if (err) {
4276 if (err == -ENOSPC) {
4277 mgmt_cmd_status(sk, hdev->id,
4278 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4279 MGMT_STATUS_NO_RESOURCES);
4280 }
4281 goto unlock;
4282 }
4283
Miao-chen Choub52729f2020-06-17 16:39:16 +02004284 if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt)
4285 mgmt_adv_monitor_added(sk, hdev, m->handle);
4286
Miao-chen Choub1395532020-06-17 16:39:14 +02004287 hci_dev_unlock(hdev);
4288
4289 rp.monitor_handle = cpu_to_le16(m->handle);
4290
4291 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4292 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4293
4294unlock:
4295 hci_dev_unlock(hdev);
4296
4297failed:
4298 hci_free_adv_monitor(m);
4299 return err;
4300}
4301
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004302static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4303 void *data, u16 len)
4304{
4305 struct mgmt_cp_remove_adv_monitor *cp = data;
4306 struct mgmt_rp_remove_adv_monitor rp;
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004307 unsigned int prev_adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004308 u16 handle;
4309 int err;
4310
4311 BT_DBG("request for %s", hdev->name);
4312
4313 hci_dev_lock(hdev);
4314
4315 handle = __le16_to_cpu(cp->monitor_handle);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004316 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004317
4318 err = hci_remove_adv_monitor(hdev, handle);
4319 if (err == -ENOENT) {
4320 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4321 MGMT_STATUS_INVALID_INDEX);
4322 goto unlock;
4323 }
4324
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004325 if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt)
4326 mgmt_adv_monitor_removed(sk, hdev, handle);
4327
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004328 hci_dev_unlock(hdev);
4329
4330 rp.monitor_handle = cp->monitor_handle;
4331
4332 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4333 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4334
4335unlock:
4336 hci_dev_unlock(hdev);
4337 return err;
4338}
4339
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004340static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4341 u16 opcode, struct sk_buff *skb)
4342{
4343 struct mgmt_rp_read_local_oob_data mgmt_rp;
4344 size_t rp_size = sizeof(mgmt_rp);
4345 struct mgmt_pending_cmd *cmd;
4346
Marcel Holtmann181d6952020-05-06 09:57:47 +02004347 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004348
4349 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4350 if (!cmd)
4351 return;
4352
4353 if (status || !skb) {
4354 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4355 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4356 goto remove;
4357 }
4358
4359 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4360
4361 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4362 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4363
4364 if (skb->len < sizeof(*rp)) {
4365 mgmt_cmd_status(cmd->sk, hdev->id,
4366 MGMT_OP_READ_LOCAL_OOB_DATA,
4367 MGMT_STATUS_FAILED);
4368 goto remove;
4369 }
4370
4371 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4372 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4373
4374 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4375 } else {
4376 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4377
4378 if (skb->len < sizeof(*rp)) {
4379 mgmt_cmd_status(cmd->sk, hdev->id,
4380 MGMT_OP_READ_LOCAL_OOB_DATA,
4381 MGMT_STATUS_FAILED);
4382 goto remove;
4383 }
4384
4385 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4386 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4387
4388 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4389 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4390 }
4391
4392 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4393 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4394
4395remove:
4396 mgmt_pending_remove(cmd);
4397}
4398
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004399static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004400 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004401{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004402 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004403 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004404 int err;
4405
Marcel Holtmann181d6952020-05-06 09:57:47 +02004406 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004408 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004409
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004410 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004411 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4412 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004413 goto unlock;
4414 }
4415
Andre Guedes9a1a1992012-07-24 15:03:48 -03004416 if (!lmp_ssp_capable(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_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004419 goto unlock;
4420 }
4421
Johan Hedberg333ae952015-03-17 13:48:47 +02004422 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, 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_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004425 goto unlock;
4426 }
4427
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004428 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004429 if (!cmd) {
4430 err = -ENOMEM;
4431 goto unlock;
4432 }
4433
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004434 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004435
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004436 if (bredr_sc_enabled(hdev))
4437 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4438 else
4439 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4440
4441 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004442 if (err < 0)
4443 mgmt_pending_remove(cmd);
4444
4445unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004446 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004447 return err;
4448}
4449
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004450static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004451 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004452{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004453 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004454 int err;
4455
Marcel Holtmann181d6952020-05-06 09:57:47 +02004456 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004457
Johan Hedberg5d57e792015-01-23 10:10:38 +02004458 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004459 return mgmt_cmd_complete(sk, hdev->id,
4460 MGMT_OP_ADD_REMOTE_OOB_DATA,
4461 MGMT_STATUS_INVALID_PARAMS,
4462 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004464 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004465
Marcel Holtmannec109112014-01-10 02:07:30 -08004466 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4467 struct mgmt_cp_add_remote_oob_data *cp = data;
4468 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004469
Johan Hedbergc19a4952014-11-17 20:52:19 +02004470 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004471 err = mgmt_cmd_complete(sk, hdev->id,
4472 MGMT_OP_ADD_REMOTE_OOB_DATA,
4473 MGMT_STATUS_INVALID_PARAMS,
4474 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004475 goto unlock;
4476 }
4477
Marcel Holtmannec109112014-01-10 02:07:30 -08004478 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004479 cp->addr.type, cp->hash,
4480 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004481 if (err < 0)
4482 status = MGMT_STATUS_FAILED;
4483 else
4484 status = MGMT_STATUS_SUCCESS;
4485
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004486 err = mgmt_cmd_complete(sk, hdev->id,
4487 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4488 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004489 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4490 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004491 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004492 u8 status;
4493
Johan Hedberg86df9202014-10-26 20:52:27 +01004494 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004495 /* Enforce zero-valued 192-bit parameters as
4496 * long as legacy SMP OOB isn't implemented.
4497 */
4498 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4499 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004500 err = mgmt_cmd_complete(sk, hdev->id,
4501 MGMT_OP_ADD_REMOTE_OOB_DATA,
4502 MGMT_STATUS_INVALID_PARAMS,
4503 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004504 goto unlock;
4505 }
4506
Johan Hedberg86df9202014-10-26 20:52:27 +01004507 rand192 = NULL;
4508 hash192 = NULL;
4509 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004510 /* In case one of the P-192 values is set to zero,
4511 * then just disable OOB data for P-192.
4512 */
4513 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4514 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4515 rand192 = NULL;
4516 hash192 = NULL;
4517 } else {
4518 rand192 = cp->rand192;
4519 hash192 = cp->hash192;
4520 }
4521 }
4522
4523 /* In case one of the P-256 values is set to zero, then just
4524 * disable OOB data for P-256.
4525 */
4526 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4527 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4528 rand256 = NULL;
4529 hash256 = NULL;
4530 } else {
4531 rand256 = cp->rand256;
4532 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004533 }
4534
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004535 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004536 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004537 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004538 if (err < 0)
4539 status = MGMT_STATUS_FAILED;
4540 else
4541 status = MGMT_STATUS_SUCCESS;
4542
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004543 err = mgmt_cmd_complete(sk, hdev->id,
4544 MGMT_OP_ADD_REMOTE_OOB_DATA,
4545 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004546 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004547 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4548 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004549 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4550 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004551 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004552
Johan Hedbergc19a4952014-11-17 20:52:19 +02004553unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004554 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004555 return err;
4556}
4557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004558static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004559 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004561 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004562 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004563 int err;
4564
Marcel Holtmann181d6952020-05-06 09:57:47 +02004565 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004566
Johan Hedbergc19a4952014-11-17 20:52:19 +02004567 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004568 return mgmt_cmd_complete(sk, hdev->id,
4569 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4570 MGMT_STATUS_INVALID_PARAMS,
4571 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004573 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004574
Johan Hedbergeedbd582014-11-15 09:34:23 +02004575 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4576 hci_remote_oob_data_clear(hdev);
4577 status = MGMT_STATUS_SUCCESS;
4578 goto done;
4579 }
4580
Johan Hedberg6928a922014-10-26 20:46:09 +01004581 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004582 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004583 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004584 else
Szymon Janca6785be2012-12-13 15:11:21 +01004585 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004586
Johan Hedbergeedbd582014-11-15 09:34:23 +02004587done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004588 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4589 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004591 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004592 return err;
4593}
4594
Johan Hedberge68f0722015-11-11 08:30:30 +02004595void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004596{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004597 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004598
Marcel Holtmann181d6952020-05-06 09:57:47 +02004599 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004600
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004601 hci_dev_lock(hdev);
4602
Johan Hedberg333ae952015-03-17 13:48:47 +02004603 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004604 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004605 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004606
Johan Hedberg78b781c2016-01-05 13:19:32 +02004607 if (!cmd)
4608 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4609
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004610 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004611 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004612 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004613 }
4614
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004615 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004616
4617 /* Handle suspend notifier */
4618 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4619 hdev->suspend_tasks)) {
4620 bt_dev_dbg(hdev, "Unpaused discovery");
4621 wake_up(&hdev->suspend_wait_q);
4622 }
Andre Guedes7c307722013-04-30 15:29:28 -03004623}
4624
Johan Hedberg591752a2015-11-11 08:11:24 +02004625static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4626 uint8_t *mgmt_status)
4627{
4628 switch (type) {
4629 case DISCOV_TYPE_LE:
4630 *mgmt_status = mgmt_le_support(hdev);
4631 if (*mgmt_status)
4632 return false;
4633 break;
4634 case DISCOV_TYPE_INTERLEAVED:
4635 *mgmt_status = mgmt_le_support(hdev);
4636 if (*mgmt_status)
4637 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05004638 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02004639 case DISCOV_TYPE_BREDR:
4640 *mgmt_status = mgmt_bredr_support(hdev);
4641 if (*mgmt_status)
4642 return false;
4643 break;
4644 default:
4645 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4646 return false;
4647 }
4648
4649 return true;
4650}
4651
Johan Hedberg78b781c2016-01-05 13:19:32 +02004652static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4653 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004654{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004655 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004656 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004657 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004658 int err;
4659
Marcel Holtmann181d6952020-05-06 09:57:47 +02004660 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004662 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004663
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004664 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004665 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004666 MGMT_STATUS_NOT_POWERED,
4667 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004668 goto failed;
4669 }
4670
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004671 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004672 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004673 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4674 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004675 goto failed;
4676 }
4677
Johan Hedberg591752a2015-11-11 08:11:24 +02004678 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004679 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4680 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004681 goto failed;
4682 }
4683
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004684 /* Can't start discovery when it is paused */
4685 if (hdev->discovery_paused) {
4686 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4687 &cp->type, sizeof(cp->type));
4688 goto failed;
4689 }
4690
Marcel Holtmann22078802014-12-05 11:45:22 +01004691 /* Clear the discovery filter first to free any previously
4692 * allocated memory for the UUID list.
4693 */
4694 hci_discovery_filter_clear(hdev);
4695
Andre Guedes4aab14e2012-02-17 20:39:36 -03004696 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004697 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004698 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4699 hdev->discovery.limited = true;
4700 else
4701 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004702
Johan Hedberg78b781c2016-01-05 13:19:32 +02004703 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004704 if (!cmd) {
4705 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004706 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004707 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004708
Johan Hedberge68f0722015-11-11 08:30:30 +02004709 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004710
4711 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004712 queue_work(hdev->req_workqueue, &hdev->discov_update);
4713 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004714
4715failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004716 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004717 return err;
4718}
4719
Johan Hedberg78b781c2016-01-05 13:19:32 +02004720static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4721 void *data, u16 len)
4722{
4723 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4724 data, len);
4725}
4726
4727static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4728 void *data, u16 len)
4729{
4730 return start_discovery_internal(sk, hdev,
4731 MGMT_OP_START_LIMITED_DISCOVERY,
4732 data, len);
4733}
4734
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004735static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4736 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004737{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004738 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4739 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004740}
4741
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004742static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4743 void *data, u16 len)
4744{
4745 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004746 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004747 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4748 u16 uuid_count, expected_len;
4749 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004750 int err;
4751
Marcel Holtmann181d6952020-05-06 09:57:47 +02004752 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004753
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004754 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004755
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004756 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004757 err = mgmt_cmd_complete(sk, hdev->id,
4758 MGMT_OP_START_SERVICE_DISCOVERY,
4759 MGMT_STATUS_NOT_POWERED,
4760 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004761 goto failed;
4762 }
4763
4764 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004765 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004766 err = mgmt_cmd_complete(sk, hdev->id,
4767 MGMT_OP_START_SERVICE_DISCOVERY,
4768 MGMT_STATUS_BUSY, &cp->type,
4769 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004770 goto failed;
4771 }
4772
4773 uuid_count = __le16_to_cpu(cp->uuid_count);
4774 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004775 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4776 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004777 err = mgmt_cmd_complete(sk, hdev->id,
4778 MGMT_OP_START_SERVICE_DISCOVERY,
4779 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4780 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004781 goto failed;
4782 }
4783
4784 expected_len = sizeof(*cp) + uuid_count * 16;
4785 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004786 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4787 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004788 err = mgmt_cmd_complete(sk, hdev->id,
4789 MGMT_OP_START_SERVICE_DISCOVERY,
4790 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4791 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004792 goto failed;
4793 }
4794
Johan Hedberg591752a2015-11-11 08:11:24 +02004795 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4796 err = mgmt_cmd_complete(sk, hdev->id,
4797 MGMT_OP_START_SERVICE_DISCOVERY,
4798 status, &cp->type, sizeof(cp->type));
4799 goto failed;
4800 }
4801
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004802 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004803 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004804 if (!cmd) {
4805 err = -ENOMEM;
4806 goto failed;
4807 }
4808
Johan Hedberg2922a942014-12-05 13:36:06 +02004809 cmd->cmd_complete = service_discovery_cmd_complete;
4810
Marcel Holtmann22078802014-12-05 11:45:22 +01004811 /* Clear the discovery filter first to free any previously
4812 * allocated memory for the UUID list.
4813 */
4814 hci_discovery_filter_clear(hdev);
4815
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004816 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004817 hdev->discovery.type = cp->type;
4818 hdev->discovery.rssi = cp->rssi;
4819 hdev->discovery.uuid_count = uuid_count;
4820
4821 if (uuid_count > 0) {
4822 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4823 GFP_KERNEL);
4824 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004825 err = mgmt_cmd_complete(sk, hdev->id,
4826 MGMT_OP_START_SERVICE_DISCOVERY,
4827 MGMT_STATUS_FAILED,
4828 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004829 mgmt_pending_remove(cmd);
4830 goto failed;
4831 }
4832 }
4833
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004834 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004835 queue_work(hdev->req_workqueue, &hdev->discov_update);
4836 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004837
4838failed:
4839 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004840 return err;
4841}
4842
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004843void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004844{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004845 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004846
Marcel Holtmann181d6952020-05-06 09:57:47 +02004847 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004848
4849 hci_dev_lock(hdev);
4850
Johan Hedberg333ae952015-03-17 13:48:47 +02004851 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004852 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004853 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004854 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004855 }
4856
Andre Guedes0e05bba2013-04-30 15:29:33 -03004857 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004858
4859 /* Handle suspend notifier */
4860 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4861 bt_dev_dbg(hdev, "Paused discovery");
4862 wake_up(&hdev->suspend_wait_q);
4863 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004864}
4865
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004866static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004867 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004868{
Johan Hedbergd9306502012-02-20 23:25:18 +02004869 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004870 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004871 int err;
4872
Marcel Holtmann181d6952020-05-06 09:57:47 +02004873 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004875 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004876
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004877 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004878 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4879 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4880 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004881 goto unlock;
4882 }
4883
4884 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004885 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4886 MGMT_STATUS_INVALID_PARAMS,
4887 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004888 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004889 }
4890
Johan Hedberg2922a942014-12-05 13:36:06 +02004891 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004892 if (!cmd) {
4893 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004894 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004895 }
4896
Johan Hedberg2922a942014-12-05 13:36:06 +02004897 cmd->cmd_complete = generic_cmd_complete;
4898
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004899 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4900 queue_work(hdev->req_workqueue, &hdev->discov_update);
4901 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004902
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004903unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004904 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004905 return err;
4906}
4907
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004908static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004909 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004910{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004911 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004912 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004913 int err;
4914
Marcel Holtmann181d6952020-05-06 09:57:47 +02004915 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004916
Johan Hedberg561aafb2012-01-04 13:31:59 +02004917 hci_dev_lock(hdev);
4918
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004919 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004920 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4921 MGMT_STATUS_FAILED, &cp->addr,
4922 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004923 goto failed;
4924 }
4925
Johan Hedberga198e7b2012-02-17 14:27:06 +02004926 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004927 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004928 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4929 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4930 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004931 goto failed;
4932 }
4933
4934 if (cp->name_known) {
4935 e->name_state = NAME_KNOWN;
4936 list_del(&e->list);
4937 } else {
4938 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004939 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004940 }
4941
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004942 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4943 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004944
4945failed:
4946 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004947 return err;
4948}
4949
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004950static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004951 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004952{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004953 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004954 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004955 int err;
4956
Marcel Holtmann181d6952020-05-06 09:57:47 +02004957 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004958
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004959 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004960 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4961 MGMT_STATUS_INVALID_PARAMS,
4962 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004963
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004964 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004965
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004966 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4967 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004968 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004969 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004970 goto done;
4971 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004972
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004973 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4974 sk);
4975 status = MGMT_STATUS_SUCCESS;
4976
4977done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004978 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4979 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004980
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004981 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004982
4983 return err;
4984}
4985
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004986static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004987 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004988{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004989 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004990 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004991 int err;
4992
Marcel Holtmann181d6952020-05-06 09:57:47 +02004993 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004994
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004995 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004996 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4997 MGMT_STATUS_INVALID_PARAMS,
4998 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005000 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005001
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005002 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
5003 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005004 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005005 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005006 goto done;
5007 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005008
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005009 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5010 sk);
5011 status = MGMT_STATUS_SUCCESS;
5012
5013done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005014 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5015 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005017 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005018
5019 return err;
5020}
5021
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005022static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5023 u16 len)
5024{
5025 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05005026 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005027 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005028 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005029
Marcel Holtmann181d6952020-05-06 09:57:47 +02005030 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005031
Szymon Jancc72d4b82012-03-16 16:02:57 +01005032 source = __le16_to_cpu(cp->source);
5033
5034 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005035 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5036 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005037
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005038 hci_dev_lock(hdev);
5039
Szymon Jancc72d4b82012-03-16 16:02:57 +01005040 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005041 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5042 hdev->devid_product = __le16_to_cpu(cp->product);
5043 hdev->devid_version = __le16_to_cpu(cp->version);
5044
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005045 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5046 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005047
Johan Hedberg890ea892013-03-15 17:06:52 -05005048 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02005049 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05005050 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005051
5052 hci_dev_unlock(hdev);
5053
5054 return err;
5055}
5056
Arman Uguray24b4f382015-03-23 15:57:12 -07005057static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5058 u16 opcode)
5059{
Marcel Holtmann181d6952020-05-06 09:57:47 +02005060 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005061}
5062
Marcel Holtmann1904a852015-01-11 13:50:44 -08005063static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5064 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005065{
5066 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005067 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005068 u8 instance;
5069 struct adv_info *adv_instance;
5070 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005071
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305072 hci_dev_lock(hdev);
5073
Johan Hedberg4375f102013-09-25 13:26:10 +03005074 if (status) {
5075 u8 mgmt_err = mgmt_status(status);
5076
5077 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5078 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305079 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005080 }
5081
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005082 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005083 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005084 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005085 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005086
Johan Hedberg4375f102013-09-25 13:26:10 +03005087 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5088 &match);
5089
5090 new_settings(hdev, match.sk);
5091
5092 if (match.sk)
5093 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305094
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005095 /* Handle suspend notifier */
5096 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5097 hdev->suspend_tasks)) {
5098 bt_dev_dbg(hdev, "Paused advertising");
5099 wake_up(&hdev->suspend_wait_q);
5100 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5101 hdev->suspend_tasks)) {
5102 bt_dev_dbg(hdev, "Unpaused advertising");
5103 wake_up(&hdev->suspend_wait_q);
5104 }
5105
Arman Uguray24b4f382015-03-23 15:57:12 -07005106 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005107 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005108 */
5109 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005110 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005111 goto unlock;
5112
Florian Grandel7816b822015-06-18 03:16:45 +02005113 instance = hdev->cur_adv_instance;
5114 if (!instance) {
5115 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5116 struct adv_info, list);
5117 if (!adv_instance)
5118 goto unlock;
5119
5120 instance = adv_instance->instance;
5121 }
5122
Arman Uguray24b4f382015-03-23 15:57:12 -07005123 hci_req_init(&req, hdev);
5124
Johan Hedbergf2252572015-11-18 12:49:20 +02005125 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005126
Florian Grandel7816b822015-06-18 03:16:45 +02005127 if (!err)
5128 err = hci_req_run(&req, enable_advertising_instance);
5129
5130 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005131 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005132
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305133unlock:
5134 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005135}
5136
Marcel Holtmann21b51872013-10-10 09:47:53 -07005137static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5138 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005139{
5140 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005141 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005142 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005143 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005144 int err;
5145
Marcel Holtmann181d6952020-05-06 09:57:47 +02005146 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005147
Johan Hedberge6fe7982013-10-02 15:45:22 +03005148 status = mgmt_le_support(hdev);
5149 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005150 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5151 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005152
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05305153 /* Enabling the experimental LL Privay support disables support for
5154 * advertising.
5155 */
5156 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
5157 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5158 MGMT_STATUS_NOT_SUPPORTED);
5159
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005160 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005161 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5162 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005163
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005164 if (hdev->advertising_paused)
5165 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5166 MGMT_STATUS_BUSY);
5167
Johan Hedberg4375f102013-09-25 13:26:10 +03005168 hci_dev_lock(hdev);
5169
5170 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005171
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005172 /* The following conditions are ones which mean that we should
5173 * not do any HCI communication but directly send a mgmt
5174 * response to user space (after toggling the flag if
5175 * necessary).
5176 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005177 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005178 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5179 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005180 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005181 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005182 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005183 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005184
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005185 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005186 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005187 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005188 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005189 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005190 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005191 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005192 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005193 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005194 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005195 }
5196
5197 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5198 if (err < 0)
5199 goto unlock;
5200
5201 if (changed)
5202 err = new_settings(hdev, sk);
5203
5204 goto unlock;
5205 }
5206
Johan Hedberg333ae952015-03-17 13:48:47 +02005207 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5208 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005209 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5210 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005211 goto unlock;
5212 }
5213
5214 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5215 if (!cmd) {
5216 err = -ENOMEM;
5217 goto unlock;
5218 }
5219
5220 hci_req_init(&req, hdev);
5221
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005222 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005223 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005224 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005225 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005226
Florian Grandel7816b822015-06-18 03:16:45 +02005227 cancel_adv_timeout(hdev);
5228
Arman Uguray24b4f382015-03-23 15:57:12 -07005229 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005230 /* Switch to instance "0" for the Set Advertising setting.
5231 * We cannot use update_[adv|scan_rsp]_data() here as the
5232 * HCI_ADVERTISING flag is not yet set.
5233 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005234 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305235
5236 if (ext_adv_capable(hdev)) {
5237 __hci_req_start_ext_adv(&req, 0x00);
5238 } else {
5239 __hci_req_update_adv_data(&req, 0x00);
5240 __hci_req_update_scan_rsp_data(&req, 0x00);
5241 __hci_req_enable_advertising(&req);
5242 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005243 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005244 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005245 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005246
5247 err = hci_req_run(&req, set_advertising_complete);
5248 if (err < 0)
5249 mgmt_pending_remove(cmd);
5250
5251unlock:
5252 hci_dev_unlock(hdev);
5253 return err;
5254}
5255
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005256static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5257 void *data, u16 len)
5258{
5259 struct mgmt_cp_set_static_address *cp = data;
5260 int err;
5261
Marcel Holtmann181d6952020-05-06 09:57:47 +02005262 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005263
Marcel Holtmann62af4442013-10-02 22:10:32 -07005264 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005265 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5266 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005267
5268 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005269 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5270 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005271
5272 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5273 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005274 return mgmt_cmd_status(sk, hdev->id,
5275 MGMT_OP_SET_STATIC_ADDRESS,
5276 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005277
5278 /* Two most significant bits shall be set */
5279 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
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
5285 hci_dev_lock(hdev);
5286
5287 bacpy(&hdev->static_addr, &cp->bdaddr);
5288
Marcel Holtmann93690c22015-03-06 10:11:21 -08005289 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5290 if (err < 0)
5291 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005292
Marcel Holtmann93690c22015-03-06 10:11:21 -08005293 err = new_settings(hdev, sk);
5294
5295unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005296 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005297 return err;
5298}
5299
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005300static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5301 void *data, u16 len)
5302{
5303 struct mgmt_cp_set_scan_params *cp = data;
5304 __u16 interval, window;
5305 int err;
5306
Marcel Holtmann181d6952020-05-06 09:57:47 +02005307 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005308
5309 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005310 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5311 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005312
5313 interval = __le16_to_cpu(cp->interval);
5314
5315 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005316 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5317 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005318
5319 window = __le16_to_cpu(cp->window);
5320
5321 if (window < 0x0004 || window > 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
Marcel Holtmann899e1072013-10-14 09:55:32 -07005325 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005326 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5327 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005328
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005329 hci_dev_lock(hdev);
5330
5331 hdev->le_scan_interval = interval;
5332 hdev->le_scan_window = window;
5333
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5335 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005336
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005337 /* If background scan is running, restart it so new parameters are
5338 * loaded.
5339 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005340 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005341 hdev->discovery.state == DISCOVERY_STOPPED) {
5342 struct hci_request req;
5343
5344 hci_req_init(&req, hdev);
5345
Sathish Narasimman5c49bcc2020-07-23 18:09:01 +05305346 hci_req_add_le_scan_disable(&req, false);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005347 hci_req_add_le_passive_scan(&req);
5348
5349 hci_req_run(&req, NULL);
5350 }
5351
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005352 hci_dev_unlock(hdev);
5353
5354 return err;
5355}
5356
Marcel Holtmann1904a852015-01-11 13:50:44 -08005357static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5358 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005359{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005360 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005361
Marcel Holtmann181d6952020-05-06 09:57:47 +02005362 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005363
5364 hci_dev_lock(hdev);
5365
Johan Hedberg333ae952015-03-17 13:48:47 +02005366 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005367 if (!cmd)
5368 goto unlock;
5369
5370 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005371 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5372 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005373 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005374 struct mgmt_mode *cp = cmd->param;
5375
5376 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005377 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005378 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005379 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005380
Johan Hedberg33e38b32013-03-15 17:07:05 -05005381 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5382 new_settings(hdev, cmd->sk);
5383 }
5384
5385 mgmt_pending_remove(cmd);
5386
5387unlock:
5388 hci_dev_unlock(hdev);
5389}
5390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005391static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005392 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005393{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005394 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005395 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005396 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005397 int err;
5398
Marcel Holtmann181d6952020-05-06 09:57:47 +02005399 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005400
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005401 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005402 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005403 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5404 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005405
Johan Hedberga7e80f22013-01-09 16:05:19 +02005406 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005407 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5408 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005409
Antti Julkuf6422ec2011-06-22 13:11:56 +03005410 hci_dev_lock(hdev);
5411
Johan Hedberg333ae952015-03-17 13:48:47 +02005412 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005413 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5414 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005415 goto unlock;
5416 }
5417
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005418 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005419 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5420 hdev);
5421 goto unlock;
5422 }
5423
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005424 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005425 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005426 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5427 hdev);
5428 new_settings(hdev, sk);
5429 goto unlock;
5430 }
5431
Johan Hedberg33e38b32013-03-15 17:07:05 -05005432 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5433 data, len);
5434 if (!cmd) {
5435 err = -ENOMEM;
5436 goto unlock;
5437 }
5438
5439 hci_req_init(&req, hdev);
5440
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005441 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005442
5443 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005444 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005445 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5446 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005447 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005448 }
5449
Johan Hedberg33e38b32013-03-15 17:07:05 -05005450unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005451 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005452
Antti Julkuf6422ec2011-06-22 13:11:56 +03005453 return err;
5454}
5455
Marcel Holtmann1904a852015-01-11 13:50:44 -08005456static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005457{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005458 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005459
Marcel Holtmann181d6952020-05-06 09:57:47 +02005460 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005461
5462 hci_dev_lock(hdev);
5463
Johan Hedberg333ae952015-03-17 13:48:47 +02005464 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005465 if (!cmd)
5466 goto unlock;
5467
5468 if (status) {
5469 u8 mgmt_err = mgmt_status(status);
5470
5471 /* We need to restore the flag if related HCI commands
5472 * failed.
5473 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005474 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005475
Johan Hedberga69e8372015-03-06 21:08:53 +02005476 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005477 } else {
5478 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5479 new_settings(hdev, cmd->sk);
5480 }
5481
5482 mgmt_pending_remove(cmd);
5483
5484unlock:
5485 hci_dev_unlock(hdev);
5486}
5487
5488static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5489{
5490 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005491 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005492 struct hci_request req;
5493 int err;
5494
Marcel Holtmann181d6952020-05-06 09:57:47 +02005495 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005496
5497 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005498 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5499 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005500
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005501 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005502 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5503 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005504
5505 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005506 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5507 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005508
5509 hci_dev_lock(hdev);
5510
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005511 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005512 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5513 goto unlock;
5514 }
5515
5516 if (!hdev_is_powered(hdev)) {
5517 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005518 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5519 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5520 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5521 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5522 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005523 }
5524
Marcel Holtmannce05d602015-03-13 02:11:03 -07005525 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005526
5527 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5528 if (err < 0)
5529 goto unlock;
5530
5531 err = new_settings(hdev, sk);
5532 goto unlock;
5533 }
5534
5535 /* Reject disabling when powered on */
5536 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005537 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5538 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005539 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005540 } else {
5541 /* When configuring a dual-mode controller to operate
5542 * with LE only and using a static address, then switching
5543 * BR/EDR back on is not allowed.
5544 *
5545 * Dual-mode controllers shall operate with the public
5546 * address as its identity address for BR/EDR and LE. So
5547 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005548 *
5549 * The same restrictions applies when secure connections
5550 * has been enabled. For BR/EDR this is a controller feature
5551 * while for LE it is a host stack feature. This means that
5552 * switching BR/EDR back on when secure connections has been
5553 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005554 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005555 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005556 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005557 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005558 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5559 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005560 goto unlock;
5561 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005562 }
5563
Johan Hedberg333ae952015-03-17 13:48:47 +02005564 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005565 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5566 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005567 goto unlock;
5568 }
5569
5570 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5571 if (!cmd) {
5572 err = -ENOMEM;
5573 goto unlock;
5574 }
5575
Johan Hedbergf2252572015-11-18 12:49:20 +02005576 /* We need to flip the bit already here so that
5577 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005578 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005579 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005580
5581 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005582
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005583 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005584 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005585
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005586 /* Since only the advertising data flags will change, there
5587 * is no need to update the scan response data.
5588 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005589 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005590
Johan Hedberg0663ca22013-10-02 13:43:14 +03005591 err = hci_req_run(&req, set_bredr_complete);
5592 if (err < 0)
5593 mgmt_pending_remove(cmd);
5594
5595unlock:
5596 hci_dev_unlock(hdev);
5597 return err;
5598}
5599
Johan Hedberga1443f52015-01-23 15:42:46 +02005600static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5601{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005602 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005603 struct mgmt_mode *cp;
5604
Marcel Holtmann181d6952020-05-06 09:57:47 +02005605 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005606
5607 hci_dev_lock(hdev);
5608
Johan Hedberg333ae952015-03-17 13:48:47 +02005609 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005610 if (!cmd)
5611 goto unlock;
5612
5613 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005614 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5615 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005616 goto remove;
5617 }
5618
5619 cp = cmd->param;
5620
5621 switch (cp->val) {
5622 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005623 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5624 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005625 break;
5626 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005627 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005628 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005629 break;
5630 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005631 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5632 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005633 break;
5634 }
5635
5636 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5637 new_settings(hdev, cmd->sk);
5638
5639remove:
5640 mgmt_pending_remove(cmd);
5641unlock:
5642 hci_dev_unlock(hdev);
5643}
5644
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005645static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5646 void *data, u16 len)
5647{
5648 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005649 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005650 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005651 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005652 int err;
5653
Marcel Holtmann181d6952020-05-06 09:57:47 +02005654 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005655
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005656 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005657 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005658 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5659 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005661 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005662 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005663 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5665 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005666
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005667 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005668 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005669 MGMT_STATUS_INVALID_PARAMS);
5670
5671 hci_dev_lock(hdev);
5672
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005673 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005674 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005675 bool changed;
5676
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005677 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005678 changed = !hci_dev_test_and_set_flag(hdev,
5679 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005680 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005681 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005682 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005683 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005684 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005685 changed = hci_dev_test_and_clear_flag(hdev,
5686 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005687 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005688 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005689
5690 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5691 if (err < 0)
5692 goto failed;
5693
5694 if (changed)
5695 err = new_settings(hdev, sk);
5696
5697 goto failed;
5698 }
5699
Johan Hedberg333ae952015-03-17 13:48:47 +02005700 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005701 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5702 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005703 goto failed;
5704 }
5705
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005706 val = !!cp->val;
5707
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005708 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5709 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005710 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5711 goto failed;
5712 }
5713
5714 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5715 if (!cmd) {
5716 err = -ENOMEM;
5717 goto failed;
5718 }
5719
Johan Hedberga1443f52015-01-23 15:42:46 +02005720 hci_req_init(&req, hdev);
5721 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5722 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005723 if (err < 0) {
5724 mgmt_pending_remove(cmd);
5725 goto failed;
5726 }
5727
5728failed:
5729 hci_dev_unlock(hdev);
5730 return err;
5731}
5732
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005733static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5734 void *data, u16 len)
5735{
5736 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005737 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005738 int err;
5739
Marcel Holtmann181d6952020-05-06 09:57:47 +02005740 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005741
Johan Hedbergb97109792014-06-24 14:00:28 +03005742 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005743 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5744 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005745
5746 hci_dev_lock(hdev);
5747
5748 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005749 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005750 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005751 changed = hci_dev_test_and_clear_flag(hdev,
5752 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005753
Johan Hedbergb97109792014-06-24 14:00:28 +03005754 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005755 use_changed = !hci_dev_test_and_set_flag(hdev,
5756 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005757 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005758 use_changed = hci_dev_test_and_clear_flag(hdev,
5759 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005760
5761 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005762 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005763 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5764 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5765 sizeof(mode), &mode);
5766 }
5767
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005768 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5769 if (err < 0)
5770 goto unlock;
5771
5772 if (changed)
5773 err = new_settings(hdev, sk);
5774
5775unlock:
5776 hci_dev_unlock(hdev);
5777 return err;
5778}
5779
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005780static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5781 u16 len)
5782{
5783 struct mgmt_cp_set_privacy *cp = cp_data;
5784 bool changed;
5785 int err;
5786
Marcel Holtmann181d6952020-05-06 09:57:47 +02005787 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005788
5789 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005790 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5791 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005792
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005793 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5795 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005796
5797 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5799 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005800
5801 hci_dev_lock(hdev);
5802
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005803 /* If user space supports this command it is also expected to
5804 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5805 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005806 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005807
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005808 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005809 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005810 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005811 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305812 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005813 if (cp->privacy == 0x02)
5814 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5815 else
5816 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005817 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005818 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005819 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005820 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305821 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005822 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005823 }
5824
5825 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5826 if (err < 0)
5827 goto unlock;
5828
5829 if (changed)
5830 err = new_settings(hdev, sk);
5831
5832unlock:
5833 hci_dev_unlock(hdev);
5834 return err;
5835}
5836
Johan Hedberg41edf162014-02-18 10:19:35 +02005837static bool irk_is_valid(struct mgmt_irk_info *irk)
5838{
5839 switch (irk->addr.type) {
5840 case BDADDR_LE_PUBLIC:
5841 return true;
5842
5843 case BDADDR_LE_RANDOM:
5844 /* Two most significant bits shall be set */
5845 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5846 return false;
5847 return true;
5848 }
5849
5850 return false;
5851}
5852
5853static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5854 u16 len)
5855{
5856 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005857 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5858 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005859 u16 irk_count, expected_len;
5860 int i, err;
5861
Marcel Holtmann181d6952020-05-06 09:57:47 +02005862 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005863
5864 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005865 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5866 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005867
5868 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005869 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005870 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5871 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005872 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5873 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005874 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005875
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005876 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005877 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005878 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5879 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005880 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5881 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005882 }
5883
Marcel Holtmann181d6952020-05-06 09:57:47 +02005884 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005885
5886 for (i = 0; i < irk_count; i++) {
5887 struct mgmt_irk_info *key = &cp->irks[i];
5888
5889 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005890 return mgmt_cmd_status(sk, hdev->id,
5891 MGMT_OP_LOAD_IRKS,
5892 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005893 }
5894
5895 hci_dev_lock(hdev);
5896
5897 hci_smp_irks_clear(hdev);
5898
5899 for (i = 0; i < irk_count; i++) {
5900 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005901
Alain Michaud600a8742020-01-07 00:43:17 +00005902 if (hci_is_blocked_key(hdev,
5903 HCI_BLOCKED_KEY_TYPE_IRK,
5904 irk->val)) {
5905 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5906 &irk->addr.bdaddr);
5907 continue;
5908 }
5909
Johan Hedberg85813a72015-10-21 18:02:59 +03005910 hci_add_irk(hdev, &irk->addr.bdaddr,
5911 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005912 BDADDR_ANY);
5913 }
5914
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005915 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005916
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005917 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005918
5919 hci_dev_unlock(hdev);
5920
5921 return err;
5922}
5923
Johan Hedberg3f706b72013-01-20 14:27:16 +02005924static bool ltk_is_valid(struct mgmt_ltk_info *key)
5925{
5926 if (key->master != 0x00 && key->master != 0x01)
5927 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005928
5929 switch (key->addr.type) {
5930 case BDADDR_LE_PUBLIC:
5931 return true;
5932
5933 case BDADDR_LE_RANDOM:
5934 /* Two most significant bits shall be set */
5935 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5936 return false;
5937 return true;
5938 }
5939
5940 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005941}
5942
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005943static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005944 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005945{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005946 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005947 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5948 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005949 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005950 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005951
Marcel Holtmann181d6952020-05-06 09:57:47 +02005952 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005953
5954 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5956 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005957
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005958 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005959 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005960 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5961 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005962 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5963 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005964 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005965
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005966 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005967 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005968 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5969 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005970 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5971 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005972 }
5973
Marcel Holtmann181d6952020-05-06 09:57:47 +02005974 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005975
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005976 for (i = 0; i < key_count; i++) {
5977 struct mgmt_ltk_info *key = &cp->keys[i];
5978
Johan Hedberg3f706b72013-01-20 14:27:16 +02005979 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005980 return mgmt_cmd_status(sk, hdev->id,
5981 MGMT_OP_LOAD_LONG_TERM_KEYS,
5982 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005983 }
5984
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005985 hci_dev_lock(hdev);
5986
5987 hci_smp_ltks_clear(hdev);
5988
5989 for (i = 0; i < key_count; i++) {
5990 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005991 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005992
Alain Michaud600a8742020-01-07 00:43:17 +00005993 if (hci_is_blocked_key(hdev,
5994 HCI_BLOCKED_KEY_TYPE_LTK,
5995 key->val)) {
5996 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5997 &key->addr.bdaddr);
5998 continue;
5999 }
6000
Johan Hedberg61b43352014-05-29 19:36:53 +03006001 switch (key->type) {
6002 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006003 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006004 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006005 break;
6006 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006007 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006008 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006009 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006010 case MGMT_LTK_P256_UNAUTH:
6011 authenticated = 0x00;
6012 type = SMP_LTK_P256;
6013 break;
6014 case MGMT_LTK_P256_AUTH:
6015 authenticated = 0x01;
6016 type = SMP_LTK_P256;
6017 break;
6018 case MGMT_LTK_P256_DEBUG:
6019 authenticated = 0x00;
6020 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006021 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006022 default:
6023 continue;
6024 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006025
Johan Hedberg85813a72015-10-21 18:02:59 +03006026 hci_add_ltk(hdev, &key->addr.bdaddr,
6027 le_addr_type(key->addr.type), type, authenticated,
6028 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006029 }
6030
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006031 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006032 NULL, 0);
6033
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006034 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006035
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006036 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006037}
6038
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006039static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006040{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006041 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006042 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006043 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006044
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006045 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006046
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006047 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006048 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006049 rp.tx_power = conn->tx_power;
6050 rp.max_tx_power = conn->max_tx_power;
6051 } else {
6052 rp.rssi = HCI_RSSI_INVALID;
6053 rp.tx_power = HCI_TX_POWER_INVALID;
6054 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006055 }
6056
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006057 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6058 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006059
6060 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006061 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006062
6063 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006064}
6065
Marcel Holtmann1904a852015-01-11 13:50:44 -08006066static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6067 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006068{
6069 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006070 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006071 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006072 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006073 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006074
Marcel Holtmann181d6952020-05-06 09:57:47 +02006075 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006076
6077 hci_dev_lock(hdev);
6078
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006079 /* Commands sent in request are either Read RSSI or Read Transmit Power
6080 * Level so we check which one was last sent to retrieve connection
6081 * handle. Both commands have handle as first parameter so it's safe to
6082 * cast data on the same command struct.
6083 *
6084 * First command sent is always Read RSSI and we fail only if it fails.
6085 * In other case we simply override error to indicate success as we
6086 * already remembered if TX power value is actually valid.
6087 */
6088 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6089 if (!cp) {
6090 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006091 status = MGMT_STATUS_SUCCESS;
6092 } else {
6093 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006094 }
6095
6096 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006097 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006098 goto unlock;
6099 }
6100
6101 handle = __le16_to_cpu(cp->handle);
6102 conn = hci_conn_hash_lookup_handle(hdev, handle);
6103 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006104 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
6105 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006106 goto unlock;
6107 }
6108
Johan Hedberg333ae952015-03-17 13:48:47 +02006109 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006110 if (!cmd)
6111 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006112
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006113 cmd->cmd_complete(cmd, status);
6114 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006115
6116unlock:
6117 hci_dev_unlock(hdev);
6118}
6119
6120static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6121 u16 len)
6122{
6123 struct mgmt_cp_get_conn_info *cp = data;
6124 struct mgmt_rp_get_conn_info rp;
6125 struct hci_conn *conn;
6126 unsigned long conn_info_age;
6127 int err = 0;
6128
Marcel Holtmann181d6952020-05-06 09:57:47 +02006129 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006130
6131 memset(&rp, 0, sizeof(rp));
6132 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6133 rp.addr.type = cp->addr.type;
6134
6135 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006136 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6137 MGMT_STATUS_INVALID_PARAMS,
6138 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006139
6140 hci_dev_lock(hdev);
6141
6142 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006143 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6144 MGMT_STATUS_NOT_POWERED, &rp,
6145 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006146 goto unlock;
6147 }
6148
6149 if (cp->addr.type == BDADDR_BREDR)
6150 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6151 &cp->addr.bdaddr);
6152 else
6153 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6154
6155 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006156 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6157 MGMT_STATUS_NOT_CONNECTED, &rp,
6158 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006159 goto unlock;
6160 }
6161
Johan Hedberg333ae952015-03-17 13:48:47 +02006162 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006163 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6164 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006165 goto unlock;
6166 }
6167
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006168 /* To avoid client trying to guess when to poll again for information we
6169 * calculate conn info age as random value between min/max set in hdev.
6170 */
6171 conn_info_age = hdev->conn_info_min_age +
6172 prandom_u32_max(hdev->conn_info_max_age -
6173 hdev->conn_info_min_age);
6174
6175 /* Query controller to refresh cached values if they are too old or were
6176 * never read.
6177 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006178 if (time_after(jiffies, conn->conn_info_timestamp +
6179 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006180 !conn->conn_info_timestamp) {
6181 struct hci_request req;
6182 struct hci_cp_read_tx_power req_txp_cp;
6183 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006184 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006185
6186 hci_req_init(&req, hdev);
6187 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6188 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6189 &req_rssi_cp);
6190
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006191 /* For LE links TX power does not change thus we don't need to
6192 * query for it once value is known.
6193 */
6194 if (!bdaddr_type_is_le(cp->addr.type) ||
6195 conn->tx_power == HCI_TX_POWER_INVALID) {
6196 req_txp_cp.handle = cpu_to_le16(conn->handle);
6197 req_txp_cp.type = 0x00;
6198 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6199 sizeof(req_txp_cp), &req_txp_cp);
6200 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006201
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006202 /* Max TX power needs to be read only once per connection */
6203 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6204 req_txp_cp.handle = cpu_to_le16(conn->handle);
6205 req_txp_cp.type = 0x01;
6206 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6207 sizeof(req_txp_cp), &req_txp_cp);
6208 }
6209
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006210 err = hci_req_run(&req, conn_info_refresh_complete);
6211 if (err < 0)
6212 goto unlock;
6213
6214 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6215 data, len);
6216 if (!cmd) {
6217 err = -ENOMEM;
6218 goto unlock;
6219 }
6220
6221 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006222 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006223 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006224
6225 conn->conn_info_timestamp = jiffies;
6226 } else {
6227 /* Cache is valid, just reply with values cached in hci_conn */
6228 rp.rssi = conn->rssi;
6229 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006230 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006231
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006232 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6233 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006234 }
6235
6236unlock:
6237 hci_dev_unlock(hdev);
6238 return err;
6239}
6240
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006241static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006242{
6243 struct hci_conn *conn = cmd->user_data;
6244 struct mgmt_rp_get_clock_info rp;
6245 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006246 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006247
6248 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006249 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006250
6251 if (status)
6252 goto complete;
6253
6254 hdev = hci_dev_get(cmd->index);
6255 if (hdev) {
6256 rp.local_clock = cpu_to_le32(hdev->clock);
6257 hci_dev_put(hdev);
6258 }
6259
6260 if (conn) {
6261 rp.piconet_clock = cpu_to_le32(conn->clock);
6262 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6263 }
6264
6265complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006266 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6267 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006268
6269 if (conn) {
6270 hci_conn_drop(conn);
6271 hci_conn_put(conn);
6272 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006273
6274 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006275}
6276
Marcel Holtmann1904a852015-01-11 13:50:44 -08006277static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006278{
Johan Hedberg95868422014-06-28 17:54:07 +03006279 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006280 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006281 struct hci_conn *conn;
6282
Marcel Holtmann181d6952020-05-06 09:57:47 +02006283 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006284
6285 hci_dev_lock(hdev);
6286
6287 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6288 if (!hci_cp)
6289 goto unlock;
6290
6291 if (hci_cp->which) {
6292 u16 handle = __le16_to_cpu(hci_cp->handle);
6293 conn = hci_conn_hash_lookup_handle(hdev, handle);
6294 } else {
6295 conn = NULL;
6296 }
6297
Johan Hedberg333ae952015-03-17 13:48:47 +02006298 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006299 if (!cmd)
6300 goto unlock;
6301
Johan Hedberg69487372014-12-05 13:36:07 +02006302 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006303 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006304
6305unlock:
6306 hci_dev_unlock(hdev);
6307}
6308
6309static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6310 u16 len)
6311{
6312 struct mgmt_cp_get_clock_info *cp = data;
6313 struct mgmt_rp_get_clock_info rp;
6314 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006315 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006316 struct hci_request req;
6317 struct hci_conn *conn;
6318 int err;
6319
Marcel Holtmann181d6952020-05-06 09:57:47 +02006320 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006321
6322 memset(&rp, 0, sizeof(rp));
6323 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6324 rp.addr.type = cp->addr.type;
6325
6326 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006327 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6328 MGMT_STATUS_INVALID_PARAMS,
6329 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006330
6331 hci_dev_lock(hdev);
6332
6333 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6335 MGMT_STATUS_NOT_POWERED, &rp,
6336 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006337 goto unlock;
6338 }
6339
6340 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6341 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6342 &cp->addr.bdaddr);
6343 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006344 err = mgmt_cmd_complete(sk, hdev->id,
6345 MGMT_OP_GET_CLOCK_INFO,
6346 MGMT_STATUS_NOT_CONNECTED,
6347 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006348 goto unlock;
6349 }
6350 } else {
6351 conn = NULL;
6352 }
6353
6354 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6355 if (!cmd) {
6356 err = -ENOMEM;
6357 goto unlock;
6358 }
6359
Johan Hedberg69487372014-12-05 13:36:07 +02006360 cmd->cmd_complete = clock_info_cmd_complete;
6361
Johan Hedberg95868422014-06-28 17:54:07 +03006362 hci_req_init(&req, hdev);
6363
6364 memset(&hci_cp, 0, sizeof(hci_cp));
6365 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6366
6367 if (conn) {
6368 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006369 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006370
6371 hci_cp.handle = cpu_to_le16(conn->handle);
6372 hci_cp.which = 0x01; /* Piconet clock */
6373 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6374 }
6375
6376 err = hci_req_run(&req, get_clock_info_complete);
6377 if (err < 0)
6378 mgmt_pending_remove(cmd);
6379
6380unlock:
6381 hci_dev_unlock(hdev);
6382 return err;
6383}
6384
Johan Hedberg5a154e62014-12-19 22:26:02 +02006385static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6386{
6387 struct hci_conn *conn;
6388
6389 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6390 if (!conn)
6391 return false;
6392
6393 if (conn->dst_type != type)
6394 return false;
6395
6396 if (conn->state != BT_CONNECTED)
6397 return false;
6398
6399 return true;
6400}
6401
6402/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006403static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006404 u8 addr_type, u8 auto_connect)
6405{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006406 struct hci_conn_params *params;
6407
6408 params = hci_conn_params_add(hdev, addr, addr_type);
6409 if (!params)
6410 return -EIO;
6411
6412 if (params->auto_connect == auto_connect)
6413 return 0;
6414
6415 list_del_init(&params->action);
6416
6417 switch (auto_connect) {
6418 case HCI_AUTO_CONN_DISABLED:
6419 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006420 /* If auto connect is being disabled when we're trying to
6421 * connect to device, keep connecting.
6422 */
6423 if (params->explicit_connect)
6424 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006425 break;
6426 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006427 if (params->explicit_connect)
6428 list_add(&params->action, &hdev->pend_le_conns);
6429 else
6430 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006431 break;
6432 case HCI_AUTO_CONN_DIRECT:
6433 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006434 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006435 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006436 break;
6437 }
6438
6439 params->auto_connect = auto_connect;
6440
Marcel Holtmann181d6952020-05-06 09:57:47 +02006441 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6442 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006443
6444 return 0;
6445}
6446
Marcel Holtmann8afef092014-06-29 22:28:34 +02006447static void device_added(struct sock *sk, struct hci_dev *hdev,
6448 bdaddr_t *bdaddr, u8 type, u8 action)
6449{
6450 struct mgmt_ev_device_added ev;
6451
6452 bacpy(&ev.addr.bdaddr, bdaddr);
6453 ev.addr.type = type;
6454 ev.action = action;
6455
6456 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6457}
6458
Marcel Holtmann2faade52014-06-29 19:44:03 +02006459static int add_device(struct sock *sk, struct hci_dev *hdev,
6460 void *data, u16 len)
6461{
6462 struct mgmt_cp_add_device *cp = data;
6463 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006464 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006465 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006466 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006467
Marcel Holtmann181d6952020-05-06 09:57:47 +02006468 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006469
Johan Hedberg66593582014-07-09 12:59:14 +03006470 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006471 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006472 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6473 MGMT_STATUS_INVALID_PARAMS,
6474 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006475
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006476 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006477 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6478 MGMT_STATUS_INVALID_PARAMS,
6479 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006480
6481 hci_dev_lock(hdev);
6482
Johan Hedberg66593582014-07-09 12:59:14 +03006483 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006484 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006485 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006486 err = mgmt_cmd_complete(sk, hdev->id,
6487 MGMT_OP_ADD_DEVICE,
6488 MGMT_STATUS_INVALID_PARAMS,
6489 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006490 goto unlock;
6491 }
6492
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006493 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6494 &cp->addr.bdaddr,
6495 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006496 if (err)
6497 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006498
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006499 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006500
Johan Hedberg66593582014-07-09 12:59:14 +03006501 goto added;
6502 }
6503
Johan Hedberg85813a72015-10-21 18:02:59 +03006504 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006505
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006506 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006507 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006508 else if (cp->action == 0x01)
6509 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006510 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006511 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006512
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006513 /* Kernel internally uses conn_params with resolvable private
6514 * address, but Add Device allows only identity addresses.
6515 * Make sure it is enforced before calling
6516 * hci_conn_params_lookup.
6517 */
6518 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006519 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6520 MGMT_STATUS_INVALID_PARAMS,
6521 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006522 goto unlock;
6523 }
6524
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006525 /* If the connection parameters don't exist for this device,
6526 * they will be created and configured with defaults.
6527 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006528 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006529 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006530 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6531 MGMT_STATUS_FAILED, &cp->addr,
6532 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006533 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006534 } else {
6535 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6536 addr_type);
6537 if (params)
6538 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006539 }
6540
Johan Hedberg51d7a942015-11-11 08:11:18 +02006541 hci_update_background_scan(hdev);
6542
Johan Hedberg66593582014-07-09 12:59:14 +03006543added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006544 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006545 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6546 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006547
Johan Hedberg51d7a942015-11-11 08:11:18 +02006548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6549 MGMT_STATUS_SUCCESS, &cp->addr,
6550 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006551
6552unlock:
6553 hci_dev_unlock(hdev);
6554 return err;
6555}
6556
Marcel Holtmann8afef092014-06-29 22:28:34 +02006557static void device_removed(struct sock *sk, struct hci_dev *hdev,
6558 bdaddr_t *bdaddr, u8 type)
6559{
6560 struct mgmt_ev_device_removed ev;
6561
6562 bacpy(&ev.addr.bdaddr, bdaddr);
6563 ev.addr.type = type;
6564
6565 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6566}
6567
Marcel Holtmann2faade52014-06-29 19:44:03 +02006568static int remove_device(struct sock *sk, struct hci_dev *hdev,
6569 void *data, u16 len)
6570{
6571 struct mgmt_cp_remove_device *cp = data;
6572 int err;
6573
Marcel Holtmann181d6952020-05-06 09:57:47 +02006574 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006575
6576 hci_dev_lock(hdev);
6577
6578 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006579 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006580 u8 addr_type;
6581
Johan Hedberg66593582014-07-09 12:59:14 +03006582 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006583 err = mgmt_cmd_complete(sk, hdev->id,
6584 MGMT_OP_REMOVE_DEVICE,
6585 MGMT_STATUS_INVALID_PARAMS,
6586 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006587 goto unlock;
6588 }
6589
Johan Hedberg66593582014-07-09 12:59:14 +03006590 if (cp->addr.type == BDADDR_BREDR) {
6591 err = hci_bdaddr_list_del(&hdev->whitelist,
6592 &cp->addr.bdaddr,
6593 cp->addr.type);
6594 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006595 err = mgmt_cmd_complete(sk, hdev->id,
6596 MGMT_OP_REMOVE_DEVICE,
6597 MGMT_STATUS_INVALID_PARAMS,
6598 &cp->addr,
6599 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006600 goto unlock;
6601 }
6602
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006603 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006604
Johan Hedberg66593582014-07-09 12:59:14 +03006605 device_removed(sk, hdev, &cp->addr.bdaddr,
6606 cp->addr.type);
6607 goto complete;
6608 }
6609
Johan Hedberg85813a72015-10-21 18:02:59 +03006610 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006611
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006612 /* Kernel internally uses conn_params with resolvable private
6613 * address, but Remove Device allows only identity addresses.
6614 * Make sure it is enforced before calling
6615 * hci_conn_params_lookup.
6616 */
6617 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006618 err = mgmt_cmd_complete(sk, hdev->id,
6619 MGMT_OP_REMOVE_DEVICE,
6620 MGMT_STATUS_INVALID_PARAMS,
6621 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006622 goto unlock;
6623 }
6624
Johan Hedbergc71593d2014-07-02 17:37:28 +03006625 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6626 addr_type);
6627 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006628 err = mgmt_cmd_complete(sk, hdev->id,
6629 MGMT_OP_REMOVE_DEVICE,
6630 MGMT_STATUS_INVALID_PARAMS,
6631 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006632 goto unlock;
6633 }
6634
Johan Hedberg679d2b62015-10-16 10:07:52 +03006635 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6636 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006637 err = mgmt_cmd_complete(sk, hdev->id,
6638 MGMT_OP_REMOVE_DEVICE,
6639 MGMT_STATUS_INVALID_PARAMS,
6640 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006641 goto unlock;
6642 }
6643
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006644 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006645 list_del(&params->list);
6646 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006647 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006648
6649 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006650 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006651 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006652 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006653
Marcel Holtmann2faade52014-06-29 19:44:03 +02006654 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006655 err = mgmt_cmd_complete(sk, hdev->id,
6656 MGMT_OP_REMOVE_DEVICE,
6657 MGMT_STATUS_INVALID_PARAMS,
6658 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006659 goto unlock;
6660 }
6661
Johan Hedberg66593582014-07-09 12:59:14 +03006662 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6663 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6664 list_del(&b->list);
6665 kfree(b);
6666 }
6667
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006668 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006669
Johan Hedberg19de0822014-07-06 13:06:51 +03006670 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6671 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6672 continue;
6673 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006674 if (p->explicit_connect) {
6675 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6676 continue;
6677 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006678 list_del(&p->action);
6679 list_del(&p->list);
6680 kfree(p);
6681 }
6682
Marcel Holtmann181d6952020-05-06 09:57:47 +02006683 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006684
Johan Hedberg51d7a942015-11-11 08:11:18 +02006685 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006686 }
6687
Johan Hedberg66593582014-07-09 12:59:14 +03006688complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006689 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6690 MGMT_STATUS_SUCCESS, &cp->addr,
6691 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006692unlock:
6693 hci_dev_unlock(hdev);
6694 return err;
6695}
6696
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006697static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6698 u16 len)
6699{
6700 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006701 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6702 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006703 u16 param_count, expected_len;
6704 int i;
6705
6706 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6708 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006709
6710 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006711 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006712 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6713 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006714 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6715 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006716 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006717
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006718 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006719 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006720 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6721 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006722 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6723 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006724 }
6725
Marcel Holtmann181d6952020-05-06 09:57:47 +02006726 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006727
6728 hci_dev_lock(hdev);
6729
6730 hci_conn_params_clear_disabled(hdev);
6731
6732 for (i = 0; i < param_count; i++) {
6733 struct mgmt_conn_param *param = &cp->params[i];
6734 struct hci_conn_params *hci_param;
6735 u16 min, max, latency, timeout;
6736 u8 addr_type;
6737
Marcel Holtmann181d6952020-05-06 09:57:47 +02006738 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6739 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006740
6741 if (param->addr.type == BDADDR_LE_PUBLIC) {
6742 addr_type = ADDR_LE_DEV_PUBLIC;
6743 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6744 addr_type = ADDR_LE_DEV_RANDOM;
6745 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006746 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006747 continue;
6748 }
6749
6750 min = le16_to_cpu(param->min_interval);
6751 max = le16_to_cpu(param->max_interval);
6752 latency = le16_to_cpu(param->latency);
6753 timeout = le16_to_cpu(param->timeout);
6754
Marcel Holtmann181d6952020-05-06 09:57:47 +02006755 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6756 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006757
6758 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006759 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006760 continue;
6761 }
6762
6763 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6764 addr_type);
6765 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006766 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006767 continue;
6768 }
6769
6770 hci_param->conn_min_interval = min;
6771 hci_param->conn_max_interval = max;
6772 hci_param->conn_latency = latency;
6773 hci_param->supervision_timeout = timeout;
6774 }
6775
6776 hci_dev_unlock(hdev);
6777
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006778 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6779 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006780}
6781
Marcel Holtmanndbece372014-07-04 18:11:55 +02006782static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6783 void *data, u16 len)
6784{
6785 struct mgmt_cp_set_external_config *cp = data;
6786 bool changed;
6787 int err;
6788
Marcel Holtmann181d6952020-05-06 09:57:47 +02006789 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006790
6791 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006792 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6793 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006794
6795 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006796 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6797 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006798
6799 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006800 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6801 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006802
6803 hci_dev_lock(hdev);
6804
6805 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006806 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006807 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006808 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006809
6810 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6811 if (err < 0)
6812 goto unlock;
6813
6814 if (!changed)
6815 goto unlock;
6816
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006817 err = new_options(hdev, sk);
6818
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006819 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006820 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006821
Marcel Holtmann516018a2015-03-13 02:11:04 -07006822 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006823 hci_dev_set_flag(hdev, HCI_CONFIG);
6824 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006825
6826 queue_work(hdev->req_workqueue, &hdev->power_on);
6827 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006828 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006829 mgmt_index_added(hdev);
6830 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006831 }
6832
6833unlock:
6834 hci_dev_unlock(hdev);
6835 return err;
6836}
6837
Marcel Holtmann9713c172014-07-06 12:11:15 +02006838static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6839 void *data, u16 len)
6840{
6841 struct mgmt_cp_set_public_address *cp = data;
6842 bool changed;
6843 int err;
6844
Marcel Holtmann181d6952020-05-06 09:57:47 +02006845 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006846
6847 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006848 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6849 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006850
6851 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006852 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6853 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006854
6855 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006856 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6857 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006858
6859 hci_dev_lock(hdev);
6860
6861 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6862 bacpy(&hdev->public_addr, &cp->bdaddr);
6863
6864 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6865 if (err < 0)
6866 goto unlock;
6867
6868 if (!changed)
6869 goto unlock;
6870
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006871 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006872 err = new_options(hdev, sk);
6873
6874 if (is_configured(hdev)) {
6875 mgmt_index_removed(hdev);
6876
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006877 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006878
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006879 hci_dev_set_flag(hdev, HCI_CONFIG);
6880 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006881
6882 queue_work(hdev->req_workqueue, &hdev->power_on);
6883 }
6884
6885unlock:
6886 hci_dev_unlock(hdev);
6887 return err;
6888}
6889
Johan Hedberg40f66c02015-04-07 21:52:22 +03006890static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6891 u16 opcode, struct sk_buff *skb)
6892{
6893 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6894 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6895 u8 *h192, *r192, *h256, *r256;
6896 struct mgmt_pending_cmd *cmd;
6897 u16 eir_len;
6898 int err;
6899
Marcel Holtmann181d6952020-05-06 09:57:47 +02006900 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006901
6902 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6903 if (!cmd)
6904 return;
6905
6906 mgmt_cp = cmd->param;
6907
6908 if (status) {
6909 status = mgmt_status(status);
6910 eir_len = 0;
6911
6912 h192 = NULL;
6913 r192 = NULL;
6914 h256 = NULL;
6915 r256 = NULL;
6916 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6917 struct hci_rp_read_local_oob_data *rp;
6918
6919 if (skb->len != sizeof(*rp)) {
6920 status = MGMT_STATUS_FAILED;
6921 eir_len = 0;
6922 } else {
6923 status = MGMT_STATUS_SUCCESS;
6924 rp = (void *)skb->data;
6925
6926 eir_len = 5 + 18 + 18;
6927 h192 = rp->hash;
6928 r192 = rp->rand;
6929 h256 = NULL;
6930 r256 = NULL;
6931 }
6932 } else {
6933 struct hci_rp_read_local_oob_ext_data *rp;
6934
6935 if (skb->len != sizeof(*rp)) {
6936 status = MGMT_STATUS_FAILED;
6937 eir_len = 0;
6938 } else {
6939 status = MGMT_STATUS_SUCCESS;
6940 rp = (void *)skb->data;
6941
6942 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6943 eir_len = 5 + 18 + 18;
6944 h192 = NULL;
6945 r192 = NULL;
6946 } else {
6947 eir_len = 5 + 18 + 18 + 18 + 18;
6948 h192 = rp->hash192;
6949 r192 = rp->rand192;
6950 }
6951
6952 h256 = rp->hash256;
6953 r256 = rp->rand256;
6954 }
6955 }
6956
6957 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6958 if (!mgmt_rp)
6959 goto done;
6960
6961 if (status)
6962 goto send_rsp;
6963
6964 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6965 hdev->dev_class, 3);
6966
6967 if (h192 && r192) {
6968 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6969 EIR_SSP_HASH_C192, h192, 16);
6970 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6971 EIR_SSP_RAND_R192, r192, 16);
6972 }
6973
6974 if (h256 && r256) {
6975 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6976 EIR_SSP_HASH_C256, h256, 16);
6977 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6978 EIR_SSP_RAND_R256, r256, 16);
6979 }
6980
6981send_rsp:
6982 mgmt_rp->type = mgmt_cp->type;
6983 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6984
6985 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6986 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6987 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6988 if (err < 0 || status)
6989 goto done;
6990
6991 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6992
6993 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6994 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6995 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6996done:
6997 kfree(mgmt_rp);
6998 mgmt_pending_remove(cmd);
6999}
7000
7001static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7002 struct mgmt_cp_read_local_oob_ext_data *cp)
7003{
7004 struct mgmt_pending_cmd *cmd;
7005 struct hci_request req;
7006 int err;
7007
7008 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7009 cp, sizeof(*cp));
7010 if (!cmd)
7011 return -ENOMEM;
7012
7013 hci_req_init(&req, hdev);
7014
7015 if (bredr_sc_enabled(hdev))
7016 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7017 else
7018 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7019
7020 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7021 if (err < 0) {
7022 mgmt_pending_remove(cmd);
7023 return err;
7024 }
7025
7026 return 0;
7027}
7028
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007029static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7030 void *data, u16 data_len)
7031{
7032 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7033 struct mgmt_rp_read_local_oob_ext_data *rp;
7034 size_t rp_len;
7035 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007036 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007037 int err;
7038
Marcel Holtmann181d6952020-05-06 09:57:47 +02007039 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007040
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007041 if (hdev_is_powered(hdev)) {
7042 switch (cp->type) {
7043 case BIT(BDADDR_BREDR):
7044 status = mgmt_bredr_support(hdev);
7045 if (status)
7046 eir_len = 0;
7047 else
7048 eir_len = 5;
7049 break;
7050 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7051 status = mgmt_le_support(hdev);
7052 if (status)
7053 eir_len = 0;
7054 else
7055 eir_len = 9 + 3 + 18 + 18 + 3;
7056 break;
7057 default:
7058 status = MGMT_STATUS_INVALID_PARAMS;
7059 eir_len = 0;
7060 break;
7061 }
7062 } else {
7063 status = MGMT_STATUS_NOT_POWERED;
7064 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007065 }
7066
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007067 rp_len = sizeof(*rp) + eir_len;
7068 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007069 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007070 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007071
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007072 if (status)
7073 goto complete;
7074
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007075 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007076
7077 eir_len = 0;
7078 switch (cp->type) {
7079 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007080 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7081 err = read_local_ssp_oob_req(hdev, sk, cp);
7082 hci_dev_unlock(hdev);
7083 if (!err)
7084 goto done;
7085
7086 status = MGMT_STATUS_FAILED;
7087 goto complete;
7088 } else {
7089 eir_len = eir_append_data(rp->eir, eir_len,
7090 EIR_CLASS_OF_DEV,
7091 hdev->dev_class, 3);
7092 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007093 break;
7094 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007095 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7096 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007097 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007098 status = MGMT_STATUS_FAILED;
7099 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007100 }
7101
Marcel Holtmanne2135682015-04-02 12:00:58 -07007102 /* This should return the active RPA, but since the RPA
7103 * is only programmed on demand, it is really hard to fill
7104 * this in at the moment. For now disallow retrieving
7105 * local out-of-band data when privacy is in use.
7106 *
7107 * Returning the identity address will not help here since
7108 * pairing happens before the identity resolving key is
7109 * known and thus the connection establishment happens
7110 * based on the RPA and not the identity address.
7111 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007112 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007113 hci_dev_unlock(hdev);
7114 status = MGMT_STATUS_REJECTED;
7115 goto complete;
7116 }
7117
7118 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7119 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7120 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7121 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007122 memcpy(addr, &hdev->static_addr, 6);
7123 addr[6] = 0x01;
7124 } else {
7125 memcpy(addr, &hdev->bdaddr, 6);
7126 addr[6] = 0x00;
7127 }
7128
7129 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7130 addr, sizeof(addr));
7131
7132 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7133 role = 0x02;
7134 else
7135 role = 0x01;
7136
7137 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7138 &role, sizeof(role));
7139
Marcel Holtmann5082a592015-03-16 12:39:00 -07007140 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7141 eir_len = eir_append_data(rp->eir, eir_len,
7142 EIR_LE_SC_CONFIRM,
7143 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007144
Marcel Holtmann5082a592015-03-16 12:39:00 -07007145 eir_len = eir_append_data(rp->eir, eir_len,
7146 EIR_LE_SC_RANDOM,
7147 rand, sizeof(rand));
7148 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007149
Johan Hedbergf2252572015-11-18 12:49:20 +02007150 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007151
7152 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7153 flags |= LE_AD_NO_BREDR;
7154
7155 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7156 &flags, sizeof(flags));
7157 break;
7158 }
7159
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007160 hci_dev_unlock(hdev);
7161
Marcel Holtmann72000df2015-03-16 16:11:21 -07007162 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7163
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007164 status = MGMT_STATUS_SUCCESS;
7165
7166complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007167 rp->type = cp->type;
7168 rp->eir_len = cpu_to_le16(eir_len);
7169
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007170 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007171 status, rp, sizeof(*rp) + eir_len);
7172 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007173 goto done;
7174
7175 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7176 rp, sizeof(*rp) + eir_len,
7177 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007178
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007179done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007180 kfree(rp);
7181
7182 return err;
7183}
7184
Arman Uguray089fa8c2015-03-25 18:53:45 -07007185static u32 get_supported_adv_flags(struct hci_dev *hdev)
7186{
7187 u32 flags = 0;
7188
7189 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7190 flags |= MGMT_ADV_FLAG_DISCOV;
7191 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7192 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007193 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007194 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007195
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307196 /* In extended adv TX_POWER returned from Set Adv Param
7197 * will be always valid.
7198 */
7199 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7200 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007201 flags |= MGMT_ADV_FLAG_TX_POWER;
7202
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307203 if (ext_adv_capable(hdev)) {
7204 flags |= MGMT_ADV_FLAG_SEC_1M;
7205
7206 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7207 flags |= MGMT_ADV_FLAG_SEC_2M;
7208
7209 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7210 flags |= MGMT_ADV_FLAG_SEC_CODED;
7211 }
7212
Arman Uguray089fa8c2015-03-25 18:53:45 -07007213 return flags;
7214}
7215
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007216static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7217 void *data, u16 data_len)
7218{
7219 struct mgmt_rp_read_adv_features *rp;
7220 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007221 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007222 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007223 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007224 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007225
Marcel Holtmann181d6952020-05-06 09:57:47 +02007226 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007227
Arman Uguray089fa8c2015-03-25 18:53:45 -07007228 if (!lmp_le_capable(hdev))
7229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7230 MGMT_STATUS_REJECTED);
7231
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307232 /* Enabling the experimental LL Privay support disables support for
7233 * advertising.
7234 */
7235 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7236 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7237 MGMT_STATUS_NOT_SUPPORTED);
7238
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007239 hci_dev_lock(hdev);
7240
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007241 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007242 rp = kmalloc(rp_len, GFP_ATOMIC);
7243 if (!rp) {
7244 hci_dev_unlock(hdev);
7245 return -ENOMEM;
7246 }
7247
Arman Uguray089fa8c2015-03-25 18:53:45 -07007248 supported_flags = get_supported_adv_flags(hdev);
7249
7250 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007251 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7252 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02007253 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007254 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007255
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007256 instance = rp->instance;
7257 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7258 *instance = adv_instance->instance;
7259 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007260 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007261
7262 hci_dev_unlock(hdev);
7263
7264 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7265 MGMT_STATUS_SUCCESS, rp, rp_len);
7266
7267 kfree(rp);
7268
7269 return err;
7270}
7271
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007272static u8 calculate_name_len(struct hci_dev *hdev)
7273{
7274 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7275
7276 return append_local_name(hdev, buf, 0);
7277}
7278
7279static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7280 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007281{
Arman Uguray4117ed72015-03-23 15:57:14 -07007282 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007283
Marcel Holtmann31a32482015-11-19 16:16:42 +01007284 if (is_adv_data) {
7285 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7286 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007287 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007288 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007289
Szymon Janc2bb368702016-09-18 12:50:05 +02007290 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007291 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007292 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007293 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007294 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007295
Szymon Janc2bb368702016-09-18 12:50:05 +02007296 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007297 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007298 }
7299
Szymon Janc2bb368702016-09-18 12:50:05 +02007300 return max_len;
7301}
7302
7303static bool flags_managed(u32 adv_flags)
7304{
7305 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7306 MGMT_ADV_FLAG_LIMITED_DISCOV |
7307 MGMT_ADV_FLAG_MANAGED_FLAGS);
7308}
7309
7310static bool tx_power_managed(u32 adv_flags)
7311{
7312 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7313}
7314
7315static bool name_managed(u32 adv_flags)
7316{
7317 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7318}
7319
7320static bool appearance_managed(u32 adv_flags)
7321{
7322 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7323}
7324
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007325static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7326 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007327{
7328 int i, cur_len;
7329 u8 max_len;
7330
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007331 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007332
Arman Uguray4117ed72015-03-23 15:57:14 -07007333 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007334 return false;
7335
Arman Uguray4117ed72015-03-23 15:57:14 -07007336 /* Make sure that the data is correctly formatted. */
7337 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7338 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007339
Szymon Janc9c9db782016-09-18 12:50:06 +02007340 if (data[i + 1] == EIR_FLAGS &&
7341 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007342 return false;
7343
Szymon Janc2bb368702016-09-18 12:50:05 +02007344 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7345 return false;
7346
7347 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7348 return false;
7349
7350 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7351 return false;
7352
7353 if (data[i + 1] == EIR_APPEARANCE &&
7354 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007355 return false;
7356
Arman Uguray24b4f382015-03-23 15:57:12 -07007357 /* If the current field length would exceed the total data
7358 * length, then it's invalid.
7359 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007360 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007361 return false;
7362 }
7363
7364 return true;
7365}
7366
Arman Uguray24b4f382015-03-23 15:57:12 -07007367static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7368 u16 opcode)
7369{
7370 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007371 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007372 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007373 struct adv_info *adv_instance, *n;
7374 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007375
Marcel Holtmann181d6952020-05-06 09:57:47 +02007376 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007377
7378 hci_dev_lock(hdev);
7379
7380 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7381
Florian Grandelfffd38b2015-06-18 03:16:47 +02007382 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7383 if (!adv_instance->pending)
7384 continue;
7385
7386 if (!status) {
7387 adv_instance->pending = false;
7388 continue;
7389 }
7390
7391 instance = adv_instance->instance;
7392
7393 if (hdev->cur_adv_instance == instance)
7394 cancel_adv_timeout(hdev);
7395
7396 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007397 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007398 }
7399
7400 if (!cmd)
7401 goto unlock;
7402
Florian Grandelfffd38b2015-06-18 03:16:47 +02007403 cp = cmd->param;
7404 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007405
7406 if (status)
7407 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7408 mgmt_status(status));
7409 else
7410 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7411 mgmt_status(status), &rp, sizeof(rp));
7412
7413 mgmt_pending_remove(cmd);
7414
7415unlock:
7416 hci_dev_unlock(hdev);
7417}
7418
7419static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7420 void *data, u16 data_len)
7421{
7422 struct mgmt_cp_add_advertising *cp = data;
7423 struct mgmt_rp_add_advertising rp;
7424 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307425 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007426 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007427 u16 timeout, duration;
7428 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7429 u8 schedule_instance = 0;
7430 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007431 int err;
7432 struct mgmt_pending_cmd *cmd;
7433 struct hci_request req;
7434
Marcel Holtmann181d6952020-05-06 09:57:47 +02007435 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007436
7437 status = mgmt_le_support(hdev);
7438 if (status)
7439 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7440 status);
7441
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307442 /* Enabling the experimental LL Privay support disables support for
7443 * advertising.
7444 */
7445 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7446 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7447 MGMT_STATUS_NOT_SUPPORTED);
7448
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007449 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7451 MGMT_STATUS_INVALID_PARAMS);
7452
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007453 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7454 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7455 MGMT_STATUS_INVALID_PARAMS);
7456
Arman Uguray24b4f382015-03-23 15:57:12 -07007457 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007458 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007459 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007460
Florian Grandelfffd38b2015-06-18 03:16:47 +02007461 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307462 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007463 */
7464 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307465 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7466 if (flags & ~supported_flags ||
7467 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007468 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7469 MGMT_STATUS_INVALID_PARAMS);
7470
7471 hci_dev_lock(hdev);
7472
Arman Uguray912098a2015-03-23 15:57:15 -07007473 if (timeout && !hdev_is_powered(hdev)) {
7474 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7475 MGMT_STATUS_REJECTED);
7476 goto unlock;
7477 }
7478
Arman Uguray24b4f382015-03-23 15:57:12 -07007479 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007480 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007481 pending_find(MGMT_OP_SET_LE, hdev)) {
7482 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7483 MGMT_STATUS_BUSY);
7484 goto unlock;
7485 }
7486
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007487 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7488 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007489 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007490 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7491 MGMT_STATUS_INVALID_PARAMS);
7492 goto unlock;
7493 }
7494
Florian Grandelfffd38b2015-06-18 03:16:47 +02007495 err = hci_add_adv_instance(hdev, cp->instance, flags,
7496 cp->adv_data_len, cp->data,
7497 cp->scan_rsp_len,
7498 cp->data + cp->adv_data_len,
7499 timeout, duration);
7500 if (err < 0) {
7501 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7502 MGMT_STATUS_FAILED);
7503 goto unlock;
7504 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007505
Florian Grandelfffd38b2015-06-18 03:16:47 +02007506 /* Only trigger an advertising added event if a new instance was
7507 * actually added.
7508 */
7509 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007510 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007511
Florian Grandelfffd38b2015-06-18 03:16:47 +02007512 if (hdev->cur_adv_instance == cp->instance) {
7513 /* If the currently advertised instance is being changed then
7514 * cancel the current advertising and schedule the next
7515 * instance. If there is only one instance then the overridden
7516 * advertising data will be visible right away.
7517 */
7518 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007519
Florian Grandelfffd38b2015-06-18 03:16:47 +02007520 next_instance = hci_get_next_instance(hdev, cp->instance);
7521 if (next_instance)
7522 schedule_instance = next_instance->instance;
7523 } else if (!hdev->adv_instance_timeout) {
7524 /* Immediately advertise the new instance if no other
7525 * instance is currently being advertised.
7526 */
7527 schedule_instance = cp->instance;
7528 }
Arman Uguray912098a2015-03-23 15:57:15 -07007529
Florian Grandelfffd38b2015-06-18 03:16:47 +02007530 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7531 * there is no instance to be advertised then we have no HCI
7532 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007533 */
7534 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007535 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7536 !schedule_instance) {
7537 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007538 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7539 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7540 goto unlock;
7541 }
7542
7543 /* We're good to go, update advertising data, parameters, and start
7544 * advertising.
7545 */
7546 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7547 data_len);
7548 if (!cmd) {
7549 err = -ENOMEM;
7550 goto unlock;
7551 }
7552
7553 hci_req_init(&req, hdev);
7554
Johan Hedbergf2252572015-11-18 12:49:20 +02007555 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007556
Florian Grandelfffd38b2015-06-18 03:16:47 +02007557 if (!err)
7558 err = hci_req_run(&req, add_advertising_complete);
7559
Joseph Hwang72da7b22020-03-10 09:31:50 -07007560 if (err < 0) {
7561 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7562 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007563 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007564 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007565
7566unlock:
7567 hci_dev_unlock(hdev);
7568
7569 return err;
7570}
7571
Arman Ugurayda9293352015-03-23 15:57:13 -07007572static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7573 u16 opcode)
7574{
7575 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007576 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007577 struct mgmt_rp_remove_advertising rp;
7578
Marcel Holtmann181d6952020-05-06 09:57:47 +02007579 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007580
7581 hci_dev_lock(hdev);
7582
7583 /* A failure status here only means that we failed to disable
7584 * advertising. Otherwise, the advertising instance has been removed,
7585 * so report success.
7586 */
7587 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7588 if (!cmd)
7589 goto unlock;
7590
Florian Grandel01948332015-06-18 03:16:48 +02007591 cp = cmd->param;
7592 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007593
7594 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7595 &rp, sizeof(rp));
7596 mgmt_pending_remove(cmd);
7597
7598unlock:
7599 hci_dev_unlock(hdev);
7600}
7601
7602static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7603 void *data, u16 data_len)
7604{
7605 struct mgmt_cp_remove_advertising *cp = data;
7606 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007607 struct mgmt_pending_cmd *cmd;
7608 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007609 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007610
Marcel Holtmann181d6952020-05-06 09:57:47 +02007611 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007612
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307613 /* Enabling the experimental LL Privay support disables support for
7614 * advertising.
7615 */
7616 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7617 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7618 MGMT_STATUS_NOT_SUPPORTED);
7619
Arman Ugurayda9293352015-03-23 15:57:13 -07007620 hci_dev_lock(hdev);
7621
Johan Hedberg952497b2015-06-18 21:05:31 +03007622 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007623 err = mgmt_cmd_status(sk, hdev->id,
7624 MGMT_OP_REMOVE_ADVERTISING,
7625 MGMT_STATUS_INVALID_PARAMS);
7626 goto unlock;
7627 }
7628
Arman Ugurayda9293352015-03-23 15:57:13 -07007629 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7630 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7631 pending_find(MGMT_OP_SET_LE, hdev)) {
7632 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7633 MGMT_STATUS_BUSY);
7634 goto unlock;
7635 }
7636
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007637 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007638 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7639 MGMT_STATUS_INVALID_PARAMS);
7640 goto unlock;
7641 }
7642
Florian Grandel01948332015-06-18 03:16:48 +02007643 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007644
Daniel Winkler37adf702020-07-14 14:16:00 -07007645 /* If we use extended advertising, instance is disabled and removed */
7646 if (ext_adv_capable(hdev)) {
7647 __hci_req_disable_ext_adv_instance(&req, cp->instance);
7648 __hci_req_remove_ext_adv_instance(&req, cp->instance);
7649 }
7650
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007651 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007652
Florian Grandel01948332015-06-18 03:16:48 +02007653 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007654 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007655
Florian Grandel01948332015-06-18 03:16:48 +02007656 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7657 * flag is set or the device isn't powered then we have no HCI
7658 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007659 */
Florian Grandel01948332015-06-18 03:16:48 +02007660 if (skb_queue_empty(&req.cmd_q) ||
7661 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007662 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307663 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007664 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007665 err = mgmt_cmd_complete(sk, hdev->id,
7666 MGMT_OP_REMOVE_ADVERTISING,
7667 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7668 goto unlock;
7669 }
7670
7671 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7672 data_len);
7673 if (!cmd) {
7674 err = -ENOMEM;
7675 goto unlock;
7676 }
7677
Arman Ugurayda9293352015-03-23 15:57:13 -07007678 err = hci_req_run(&req, remove_advertising_complete);
7679 if (err < 0)
7680 mgmt_pending_remove(cmd);
7681
7682unlock:
7683 hci_dev_unlock(hdev);
7684
7685 return err;
7686}
7687
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007688static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7689 void *data, u16 data_len)
7690{
7691 struct mgmt_cp_get_adv_size_info *cp = data;
7692 struct mgmt_rp_get_adv_size_info rp;
7693 u32 flags, supported_flags;
7694 int err;
7695
Marcel Holtmann181d6952020-05-06 09:57:47 +02007696 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007697
7698 if (!lmp_le_capable(hdev))
7699 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7700 MGMT_STATUS_REJECTED);
7701
7702 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7703 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7704 MGMT_STATUS_INVALID_PARAMS);
7705
7706 flags = __le32_to_cpu(cp->flags);
7707
7708 /* The current implementation only supports a subset of the specified
7709 * flags.
7710 */
7711 supported_flags = get_supported_adv_flags(hdev);
7712 if (flags & ~supported_flags)
7713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7714 MGMT_STATUS_INVALID_PARAMS);
7715
7716 rp.instance = cp->instance;
7717 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007718 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7719 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007720
7721 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7722 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7723
7724 return err;
7725}
7726
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007727static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007728 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007729 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007730 HCI_MGMT_NO_HDEV |
7731 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007732 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007733 HCI_MGMT_NO_HDEV |
7734 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007735 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007736 HCI_MGMT_NO_HDEV |
7737 HCI_MGMT_UNTRUSTED },
7738 { read_controller_info, MGMT_READ_INFO_SIZE,
7739 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007740 { set_powered, MGMT_SETTING_SIZE },
7741 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7742 { set_connectable, MGMT_SETTING_SIZE },
7743 { set_fast_connectable, MGMT_SETTING_SIZE },
7744 { set_bondable, MGMT_SETTING_SIZE },
7745 { set_link_security, MGMT_SETTING_SIZE },
7746 { set_ssp, MGMT_SETTING_SIZE },
7747 { set_hs, MGMT_SETTING_SIZE },
7748 { set_le, MGMT_SETTING_SIZE },
7749 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7750 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7751 { add_uuid, MGMT_ADD_UUID_SIZE },
7752 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007753 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7754 HCI_MGMT_VAR_LEN },
7755 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7756 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007757 { disconnect, MGMT_DISCONNECT_SIZE },
7758 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7759 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7760 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7761 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7762 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7763 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7764 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7765 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7766 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7767 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7768 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007769 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7770 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7771 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007772 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7773 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7774 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7775 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7776 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7777 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7778 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7779 { set_advertising, MGMT_SETTING_SIZE },
7780 { set_bredr, MGMT_SETTING_SIZE },
7781 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7782 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7783 { set_secure_conn, MGMT_SETTING_SIZE },
7784 { set_debug_keys, MGMT_SETTING_SIZE },
7785 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007786 { load_irks, MGMT_LOAD_IRKS_SIZE,
7787 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007788 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7789 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7790 { add_device, MGMT_ADD_DEVICE_SIZE },
7791 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007792 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7793 HCI_MGMT_VAR_LEN },
7794 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007795 HCI_MGMT_NO_HDEV |
7796 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007797 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007798 HCI_MGMT_UNCONFIGURED |
7799 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007800 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7801 HCI_MGMT_UNCONFIGURED },
7802 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7803 HCI_MGMT_UNCONFIGURED },
7804 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7805 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007806 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007807 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007808 HCI_MGMT_NO_HDEV |
7809 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007810 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007811 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7812 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007813 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007814 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007815 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007816 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7817 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007818 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307819 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307820 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007821 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7822 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007823 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007824 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7825 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007826 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7827 HCI_MGMT_UNTRUSTED |
7828 HCI_MGMT_HDEV_OPTIONAL },
7829 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7830 HCI_MGMT_VAR_LEN |
7831 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007832 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7833 HCI_MGMT_UNTRUSTED },
7834 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7835 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007836 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7837 HCI_MGMT_UNTRUSTED },
7838 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7839 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007840 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7841 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007842 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02007843 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
7844 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02007845 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007846};
7847
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007848void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007849{
Marcel Holtmannced85542015-03-14 19:27:56 -07007850 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007851
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007852 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7853 return;
7854
Marcel Holtmannf9207332015-03-14 19:27:55 -07007855 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007856 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007857 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7858 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7859 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007860 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007861 } else {
7862 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7863 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007864 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007865 }
7866 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007867 case HCI_AMP:
7868 ev.type = 0x02;
7869 break;
7870 default:
7871 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007872 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007873
7874 ev.bus = hdev->bus;
7875
7876 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7877 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007878}
7879
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007880void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007881{
Marcel Holtmannced85542015-03-14 19:27:56 -07007882 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007883 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007884
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007885 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7886 return;
7887
Marcel Holtmannf9207332015-03-14 19:27:55 -07007888 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007889 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007890 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007891
Marcel Holtmannf9207332015-03-14 19:27:55 -07007892 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7893 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7894 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007895 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007896 } else {
7897 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7898 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007899 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007900 }
7901 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007902 case HCI_AMP:
7903 ev.type = 0x02;
7904 break;
7905 default:
7906 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007907 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007908
7909 ev.bus = hdev->bus;
7910
7911 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7912 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007913}
7914
Andre Guedes6046dc32014-02-26 20:21:51 -03007915/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007916static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007917{
7918 struct hci_conn_params *p;
7919
7920 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007921 /* Needed for AUTO_OFF case where might not "really"
7922 * have been powered off.
7923 */
7924 list_del_init(&p->action);
7925
7926 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007927 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007928 case HCI_AUTO_CONN_ALWAYS:
7929 list_add(&p->action, &hdev->pend_le_conns);
7930 break;
7931 case HCI_AUTO_CONN_REPORT:
7932 list_add(&p->action, &hdev->pend_le_reports);
7933 break;
7934 default:
7935 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007936 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007937 }
7938}
7939
Johan Hedberg2ff13892015-11-25 16:15:44 +02007940void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007941{
7942 struct cmd_lookup match = { NULL, hdev };
7943
Marcel Holtmann181d6952020-05-06 09:57:47 +02007944 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007945
Johan Hedberg2ff13892015-11-25 16:15:44 +02007946 hci_dev_lock(hdev);
7947
7948 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007949 restart_le_actions(hdev);
7950 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007951 }
7952
Johan Hedberg229ab392013-03-15 17:06:53 -05007953 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7954
7955 new_settings(hdev, match.sk);
7956
Johan Hedberg229ab392013-03-15 17:06:53 -05007957 if (match.sk)
7958 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007959
7960 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007961}
7962
Johan Hedberg2ff13892015-11-25 16:15:44 +02007963void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007964{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007965 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007966 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007967
Johan Hedberg229ab392013-03-15 17:06:53 -05007968 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007969
7970 /* If the power off is because of hdev unregistration let
7971 * use the appropriate INVALID_INDEX status. Otherwise use
7972 * NOT_POWERED. We cover both scenarios here since later in
7973 * mgmt_index_removed() any hci_conn callbacks will have already
7974 * been triggered, potentially causing misleading DISCONNECTED
7975 * status responses.
7976 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007977 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007978 status = MGMT_STATUS_INVALID_INDEX;
7979 else
7980 status = MGMT_STATUS_NOT_POWERED;
7981
7982 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007983
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007984 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007985 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7986 zero_cod, sizeof(zero_cod),
7987 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007988 ext_info_changed(hdev, NULL);
7989 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007990
Johan Hedberg2ff13892015-11-25 16:15:44 +02007991 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007992
7993 if (match.sk)
7994 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007995}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007996
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007997void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007998{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007999 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008000 u8 status;
8001
Johan Hedberg333ae952015-03-17 13:48:47 +02008002 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008003 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008004 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008005
8006 if (err == -ERFKILL)
8007 status = MGMT_STATUS_RFKILLED;
8008 else
8009 status = MGMT_STATUS_FAILED;
8010
Johan Hedberga69e8372015-03-06 21:08:53 +02008011 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008012
8013 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008014}
8015
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008016void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8017 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008018{
Johan Hedberg86742e12011-11-07 23:13:38 +02008019 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008020
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008021 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008022
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008023 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008024 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008025 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008026 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008027 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008028 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008029
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008030 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008031}
Johan Hedbergf7520542011-01-20 12:34:39 +02008032
Johan Hedbergd7b25452014-05-23 13:19:53 +03008033static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8034{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008035 switch (ltk->type) {
8036 case SMP_LTK:
8037 case SMP_LTK_SLAVE:
8038 if (ltk->authenticated)
8039 return MGMT_LTK_AUTHENTICATED;
8040 return MGMT_LTK_UNAUTHENTICATED;
8041 case SMP_LTK_P256:
8042 if (ltk->authenticated)
8043 return MGMT_LTK_P256_AUTH;
8044 return MGMT_LTK_P256_UNAUTH;
8045 case SMP_LTK_P256_DEBUG:
8046 return MGMT_LTK_P256_DEBUG;
8047 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008048
8049 return MGMT_LTK_UNAUTHENTICATED;
8050}
8051
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008052void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008053{
8054 struct mgmt_ev_new_long_term_key ev;
8055
8056 memset(&ev, 0, sizeof(ev));
8057
Marcel Holtmann5192d302014-02-19 17:11:58 -08008058 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008059 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008060 * to store long term keys. Their addresses will change the
8061 * next time around.
8062 *
8063 * Only when a remote device provides an identity address
8064 * make sure the long term key is stored. If the remote
8065 * identity is known, the long term keys are internally
8066 * mapped to the identity address. So allow static random
8067 * and public addresses here.
8068 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008069 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8070 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8071 ev.store_hint = 0x00;
8072 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008073 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008074
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008075 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008076 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008077 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008078 ev.key.enc_size = key->enc_size;
8079 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008080 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008081
Johan Hedberg2ceba532014-06-16 19:25:16 +03008082 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008083 ev.key.master = 1;
8084
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008085 /* Make sure we copy only the significant bytes based on the
8086 * encryption key size, and set the rest of the value to zeroes.
8087 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008088 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008089 memset(ev.key.val + key->enc_size, 0,
8090 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008091
Marcel Holtmann083368f2013-10-15 14:26:29 -07008092 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008093}
8094
Johan Hedbergcad20c22015-10-12 13:36:19 +02008095void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008096{
8097 struct mgmt_ev_new_irk ev;
8098
8099 memset(&ev, 0, sizeof(ev));
8100
Johan Hedbergcad20c22015-10-12 13:36:19 +02008101 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008102
Johan Hedberg95fbac82014-02-19 15:18:31 +02008103 bacpy(&ev.rpa, &irk->rpa);
8104 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8105 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8106 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8107
8108 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8109}
8110
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008111void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8112 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008113{
8114 struct mgmt_ev_new_csrk ev;
8115
8116 memset(&ev, 0, sizeof(ev));
8117
8118 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008119 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008120 * to store signature resolving keys. Their addresses will change
8121 * the next time around.
8122 *
8123 * Only when a remote device provides an identity address
8124 * make sure the signature resolving key is stored. So allow
8125 * static random and public addresses here.
8126 */
8127 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8128 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8129 ev.store_hint = 0x00;
8130 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008131 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008132
8133 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8134 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008135 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008136 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8137
8138 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8139}
8140
Andre Guedesffb5a8272014-07-01 18:10:11 -03008141void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008142 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8143 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008144{
8145 struct mgmt_ev_new_conn_param ev;
8146
Johan Hedbergc103aea2014-07-02 17:37:34 +03008147 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8148 return;
8149
Andre Guedesffb5a8272014-07-01 18:10:11 -03008150 memset(&ev, 0, sizeof(ev));
8151 bacpy(&ev.addr.bdaddr, bdaddr);
8152 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008153 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008154 ev.min_interval = cpu_to_le16(min_interval);
8155 ev.max_interval = cpu_to_le16(max_interval);
8156 ev.latency = cpu_to_le16(latency);
8157 ev.timeout = cpu_to_le16(timeout);
8158
8159 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8160}
8161
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008162void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
8163 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008164{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008165 char buf[512];
8166 struct mgmt_ev_device_connected *ev = (void *) buf;
8167 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008168
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008169 bacpy(&ev->addr.bdaddr, &conn->dst);
8170 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008171
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008172 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008173
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008174 /* We must ensure that the EIR Data fields are ordered and
8175 * unique. Keep it simple for now and avoid the problem by not
8176 * adding any BR/EDR data to the LE adv.
8177 */
8178 if (conn->le_adv_data_len > 0) {
8179 memcpy(&ev->eir[eir_len],
8180 conn->le_adv_data, conn->le_adv_data_len);
8181 eir_len = conn->le_adv_data_len;
8182 } else {
8183 if (name_len > 0)
8184 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8185 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008186
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008187 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008188 eir_len = eir_append_data(ev->eir, eir_len,
8189 EIR_CLASS_OF_DEV,
8190 conn->dev_class, 3);
8191 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008192
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008193 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008194
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008195 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8196 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008197}
8198
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008199static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008200{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008201 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008202
Johan Hedbergf5818c22014-12-05 13:36:02 +02008203 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008204
8205 *sk = cmd->sk;
8206 sock_hold(*sk);
8207
Johan Hedberga664b5b2011-02-19 12:06:02 -03008208 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008209}
8210
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008211static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008212{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008213 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008214 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008215
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008216 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8217
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008218 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008219 mgmt_pending_remove(cmd);
8220}
8221
Johan Hedberg84c61d92014-08-01 11:13:30 +03008222bool mgmt_powering_down(struct hci_dev *hdev)
8223{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008224 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008225 struct mgmt_mode *cp;
8226
Johan Hedberg333ae952015-03-17 13:48:47 +02008227 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008228 if (!cmd)
8229 return false;
8230
8231 cp = cmd->param;
8232 if (!cp->val)
8233 return true;
8234
8235 return false;
8236}
8237
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008238void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008239 u8 link_type, u8 addr_type, u8 reason,
8240 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008241{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008242 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008243 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008244
Johan Hedberg84c61d92014-08-01 11:13:30 +03008245 /* The connection is still in hci_conn_hash so test for 1
8246 * instead of 0 to know if this is the last one.
8247 */
8248 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8249 cancel_delayed_work(&hdev->power_off);
8250 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008251 }
8252
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008253 if (!mgmt_connected)
8254 return;
8255
Andre Guedes57eb7762013-10-30 19:01:41 -03008256 if (link_type != ACL_LINK && link_type != LE_LINK)
8257 return;
8258
Johan Hedberg744cf192011-11-08 20:40:14 +02008259 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008260
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008261 bacpy(&ev.addr.bdaddr, bdaddr);
8262 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8263 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008264
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008265 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008266
8267 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008268 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008269
Johan Hedberg124f6e32012-02-09 13:50:12 +02008270 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008271 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008272}
8273
Marcel Holtmann78929242013-10-06 23:55:47 -07008274void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8275 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008276{
Andre Guedes3655bba2013-10-30 19:01:40 -03008277 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8278 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008279 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008280
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008281 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8282 hdev);
8283
Johan Hedberg333ae952015-03-17 13:48:47 +02008284 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008285 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008286 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008287
Andre Guedes3655bba2013-10-30 19:01:40 -03008288 cp = cmd->param;
8289
8290 if (bacmp(bdaddr, &cp->addr.bdaddr))
8291 return;
8292
8293 if (cp->addr.type != bdaddr_type)
8294 return;
8295
Johan Hedbergf5818c22014-12-05 13:36:02 +02008296 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008297 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008298}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008299
Marcel Holtmann445608d2013-10-06 23:55:48 -07008300void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8301 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008302{
8303 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008304
Johan Hedberg84c61d92014-08-01 11:13:30 +03008305 /* The connection is still in hci_conn_hash so test for 1
8306 * instead of 0 to know if this is the last one.
8307 */
8308 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8309 cancel_delayed_work(&hdev->power_off);
8310 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008311 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008312
Johan Hedberg4c659c32011-11-07 23:13:39 +02008313 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008314 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008315 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008316
Marcel Holtmann445608d2013-10-06 23:55:48 -07008317 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008318}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008319
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008320void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008321{
8322 struct mgmt_ev_pin_code_request ev;
8323
Johan Hedbergd8457692012-02-17 14:24:57 +02008324 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008325 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008326 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008327
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008328 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008329}
8330
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008331void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8332 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008333{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008334 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008335
Johan Hedberg333ae952015-03-17 13:48:47 +02008336 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008337 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008338 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008339
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008340 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008341 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008342}
8343
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008344void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8345 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008346{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008347 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008348
Johan Hedberg333ae952015-03-17 13:48:47 +02008349 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008350 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008351 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008352
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008353 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008354 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008355}
Johan Hedberga5c29682011-02-19 12:05:57 -03008356
Johan Hedberg744cf192011-11-08 20:40:14 +02008357int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008358 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008359 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008360{
8361 struct mgmt_ev_user_confirm_request ev;
8362
Marcel Holtmann181d6952020-05-06 09:57:47 +02008363 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008364
Johan Hedberg272d90d2012-02-09 15:26:12 +02008365 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008366 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008367 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008368 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008369
Johan Hedberg744cf192011-11-08 20:40:14 +02008370 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008371 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008372}
8373
Johan Hedberg272d90d2012-02-09 15:26:12 +02008374int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008375 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008376{
8377 struct mgmt_ev_user_passkey_request ev;
8378
Marcel Holtmann181d6952020-05-06 09:57:47 +02008379 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008380
Johan Hedberg272d90d2012-02-09 15:26:12 +02008381 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008382 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008383
8384 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008385 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008386}
8387
Brian Gix0df4c182011-11-16 13:53:13 -08008388static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008389 u8 link_type, u8 addr_type, u8 status,
8390 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008391{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008392 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008393
Johan Hedberg333ae952015-03-17 13:48:47 +02008394 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008395 if (!cmd)
8396 return -ENOENT;
8397
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008398 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008399 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008400
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008401 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008402}
8403
Johan Hedberg744cf192011-11-08 20:40:14 +02008404int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008405 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008406{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008407 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008408 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008409}
8410
Johan Hedberg272d90d2012-02-09 15:26:12 +02008411int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008412 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008413{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008414 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008415 status,
8416 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008417}
Johan Hedberg2a611692011-02-19 12:06:00 -03008418
Brian Gix604086b2011-11-23 08:28:33 -08008419int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008420 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008421{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008422 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008423 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008424}
8425
Johan Hedberg272d90d2012-02-09 15:26:12 +02008426int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008427 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008428{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008429 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008430 status,
8431 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008432}
8433
Johan Hedberg92a25252012-09-06 18:39:26 +03008434int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8435 u8 link_type, u8 addr_type, u32 passkey,
8436 u8 entered)
8437{
8438 struct mgmt_ev_passkey_notify ev;
8439
Marcel Holtmann181d6952020-05-06 09:57:47 +02008440 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008441
8442 bacpy(&ev.addr.bdaddr, bdaddr);
8443 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8444 ev.passkey = __cpu_to_le32(passkey);
8445 ev.entered = entered;
8446
8447 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8448}
8449
Johan Hedberge1e930f2014-09-08 17:09:49 -07008450void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008451{
8452 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008453 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008454 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008455
Johan Hedberge1e930f2014-09-08 17:09:49 -07008456 bacpy(&ev.addr.bdaddr, &conn->dst);
8457 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8458 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008459
Johan Hedberge1e930f2014-09-08 17:09:49 -07008460 cmd = find_pairing(conn);
8461
8462 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8463 cmd ? cmd->sk : NULL);
8464
Johan Hedberga511b352014-12-11 21:45:45 +02008465 if (cmd) {
8466 cmd->cmd_complete(cmd, status);
8467 mgmt_pending_remove(cmd);
8468 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008469}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008470
Marcel Holtmann464996a2013-10-15 14:26:24 -07008471void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008472{
8473 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008474 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008475
8476 if (status) {
8477 u8 mgmt_err = mgmt_status(status);
8478 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008479 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008480 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008481 }
8482
Marcel Holtmann464996a2013-10-15 14:26:24 -07008483 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008484 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008485 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008486 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008487
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008488 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008489 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008490
Johan Hedberg47990ea2012-02-22 11:58:37 +02008491 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008492 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008493
8494 if (match.sk)
8495 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008496}
8497
Johan Hedberg890ea892013-03-15 17:06:52 -05008498static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008499{
Johan Hedberg890ea892013-03-15 17:06:52 -05008500 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008501 struct hci_cp_write_eir cp;
8502
Johan Hedberg976eb202012-10-24 21:12:01 +03008503 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008504 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008505
Johan Hedbergc80da272012-02-22 15:38:48 +02008506 memset(hdev->eir, 0, sizeof(hdev->eir));
8507
Johan Hedbergcacaf522012-02-21 00:52:42 +02008508 memset(&cp, 0, sizeof(cp));
8509
Johan Hedberg890ea892013-03-15 17:06:52 -05008510 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008511}
8512
Marcel Holtmann3e248562013-10-15 14:26:25 -07008513void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008514{
8515 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008516 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008517 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008518
8519 if (status) {
8520 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008521
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008522 if (enable && hci_dev_test_and_clear_flag(hdev,
8523 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008524 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008525 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008526 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008527
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008528 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8529 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008530 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008531 }
8532
8533 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008534 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008535 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008536 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008537 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008538 changed = hci_dev_test_and_clear_flag(hdev,
8539 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008540 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008541 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008542 }
8543
8544 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8545
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008546 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008547 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008548
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008549 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008550 sock_put(match.sk);
8551
Johan Hedberg890ea892013-03-15 17:06:52 -05008552 hci_req_init(&req, hdev);
8553
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008554 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8555 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008556 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8557 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008558 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008559 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008560 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008561 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008562
8563 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008564}
8565
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008566static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008567{
8568 struct cmd_lookup *match = data;
8569
Johan Hedberg90e70452012-02-23 23:09:40 +02008570 if (match->sk == NULL) {
8571 match->sk = cmd->sk;
8572 sock_hold(match->sk);
8573 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008574}
8575
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008576void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8577 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008578{
Johan Hedberg90e70452012-02-23 23:09:40 +02008579 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008580
Johan Hedberg92da6092013-03-15 17:06:55 -05008581 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8582 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8583 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008584
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008585 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008586 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8587 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008588 ext_info_changed(hdev, NULL);
8589 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008590
8591 if (match.sk)
8592 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008593}
8594
Marcel Holtmann7667da32013-10-15 14:26:27 -07008595void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008596{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008597 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008598 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008599
Johan Hedberg13928972013-03-15 17:07:00 -05008600 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008601 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008602
8603 memset(&ev, 0, sizeof(ev));
8604 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008605 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008606
Johan Hedberg333ae952015-03-17 13:48:47 +02008607 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008608 if (!cmd) {
8609 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008610
Johan Hedberg13928972013-03-15 17:07:00 -05008611 /* If this is a HCI command related to powering on the
8612 * HCI dev don't send any mgmt signals.
8613 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008614 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008615 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008616 }
8617
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008618 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8619 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008620 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008621}
Szymon Jancc35938b2011-03-22 13:12:21 +01008622
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008623static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8624{
8625 int i;
8626
8627 for (i = 0; i < uuid_count; i++) {
8628 if (!memcmp(uuid, uuids[i], 16))
8629 return true;
8630 }
8631
8632 return false;
8633}
8634
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008635static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8636{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008637 u16 parsed = 0;
8638
8639 while (parsed < eir_len) {
8640 u8 field_len = eir[0];
8641 u8 uuid[16];
8642 int i;
8643
8644 if (field_len == 0)
8645 break;
8646
8647 if (eir_len - parsed < field_len + 1)
8648 break;
8649
8650 switch (eir[1]) {
8651 case EIR_UUID16_ALL:
8652 case EIR_UUID16_SOME:
8653 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008654 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008655 uuid[13] = eir[i + 3];
8656 uuid[12] = eir[i + 2];
8657 if (has_uuid(uuid, uuid_count, uuids))
8658 return true;
8659 }
8660 break;
8661 case EIR_UUID32_ALL:
8662 case EIR_UUID32_SOME:
8663 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008664 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008665 uuid[15] = eir[i + 5];
8666 uuid[14] = eir[i + 4];
8667 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_UUID128_ALL:
8674 case EIR_UUID128_SOME:
8675 for (i = 0; i + 17 <= field_len; i += 16) {
8676 memcpy(uuid, eir + i + 2, 16);
8677 if (has_uuid(uuid, uuid_count, uuids))
8678 return true;
8679 }
8680 break;
8681 }
8682
8683 parsed += field_len + 1;
8684 eir += field_len + 1;
8685 }
8686
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008687 return false;
8688}
8689
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008690static void restart_le_scan(struct hci_dev *hdev)
8691{
8692 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008693 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008694 return;
8695
8696 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8697 hdev->discovery.scan_start +
8698 hdev->discovery.scan_duration))
8699 return;
8700
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008701 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008702 DISCOV_LE_RESTART_DELAY);
8703}
8704
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008705static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8706 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8707{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008708 /* If a RSSI threshold has been specified, and
8709 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8710 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8711 * is set, let it through for further processing, as we might need to
8712 * restart the scan.
8713 *
8714 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8715 * the results are also dropped.
8716 */
8717 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8718 (rssi == HCI_RSSI_INVALID ||
8719 (rssi < hdev->discovery.rssi &&
8720 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8721 return false;
8722
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008723 if (hdev->discovery.uuid_count != 0) {
8724 /* If a list of UUIDs is provided in filter, results with no
8725 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008726 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008727 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8728 hdev->discovery.uuids) &&
8729 !eir_has_uuids(scan_rsp, scan_rsp_len,
8730 hdev->discovery.uuid_count,
8731 hdev->discovery.uuids))
8732 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008733 }
8734
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008735 /* If duplicate filtering does not report RSSI changes, then restart
8736 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008737 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008738 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8739 restart_le_scan(hdev);
8740
8741 /* Validate RSSI value against the RSSI threshold once more. */
8742 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8743 rssi < hdev->discovery.rssi)
8744 return false;
8745 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008746
8747 return true;
8748}
8749
Marcel Holtmann901801b2013-10-06 23:55:51 -07008750void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008751 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8752 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008753{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008754 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008755 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008756 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008757
Johan Hedberg75ce2082014-07-02 22:42:01 +03008758 /* Don't send events for a non-kernel initiated discovery. With
8759 * LE one exception is if we have pend_le_reports > 0 in which
8760 * case we're doing passive scanning and want these events.
8761 */
8762 if (!hci_discovery_active(hdev)) {
8763 if (link_type == ACL_LINK)
8764 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008765 if (link_type == LE_LINK &&
8766 list_empty(&hdev->pend_le_reports) &&
8767 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03008768 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008769 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03008770 }
Andre Guedes12602d02013-04-30 15:29:40 -03008771
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008772 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008773 /* We are using service discovery */
8774 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8775 scan_rsp_len))
8776 return;
8777 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008778
Johan Hedberg78b781c2016-01-05 13:19:32 +02008779 if (hdev->discovery.limited) {
8780 /* Check for limited discoverable bit */
8781 if (dev_class) {
8782 if (!(dev_class[1] & 0x20))
8783 return;
8784 } else {
8785 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8786 if (!flags || !(flags[0] & LE_AD_LIMITED))
8787 return;
8788 }
8789 }
8790
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008791 /* Make sure that the buffer is big enough. The 5 extra bytes
8792 * are for the potential CoD field.
8793 */
8794 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008795 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008796
Johan Hedberg1dc06092012-01-15 21:01:23 +02008797 memset(buf, 0, sizeof(buf));
8798
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008799 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8800 * RSSI value was reported as 0 when not available. This behavior
8801 * is kept when using device discovery. This is required for full
8802 * backwards compatibility with the API.
8803 *
8804 * However when using service discovery, the value 127 will be
8805 * returned when the RSSI is not available.
8806 */
Szymon Janc91200e92015-01-22 16:57:05 +01008807 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8808 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008809 rssi = 0;
8810
Johan Hedberg841c5642014-07-07 12:45:54 +03008811 bacpy(&ev->addr.bdaddr, bdaddr);
8812 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008813 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008814 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008815
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008816 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008817 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008818 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008819
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008820 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8821 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008822 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008823 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008824
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008825 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008826 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008827 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008828
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008829 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8830 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008831
Marcel Holtmann901801b2013-10-06 23:55:51 -07008832 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008833}
Johan Hedberga88a9652011-03-30 13:18:12 +03008834
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008835void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8836 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008837{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008838 struct mgmt_ev_device_found *ev;
8839 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8840 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008841
Johan Hedbergb644ba32012-01-17 21:48:47 +02008842 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008843
Johan Hedbergb644ba32012-01-17 21:48:47 +02008844 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008845
Johan Hedbergb644ba32012-01-17 21:48:47 +02008846 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008847 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008848 ev->rssi = rssi;
8849
8850 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008851 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008852
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008853 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008854
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008855 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008856}
Johan Hedberg314b2382011-04-27 10:29:57 -04008857
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008858void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008859{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008860 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008861
Marcel Holtmann181d6952020-05-06 09:57:47 +02008862 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008863
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008864 memset(&ev, 0, sizeof(ev));
8865 ev.type = hdev->discovery.type;
8866 ev.discovering = discovering;
8867
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008868 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008869}
Antti Julku5e762442011-08-25 16:48:02 +03008870
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008871static struct hci_mgmt_chan chan = {
8872 .channel = HCI_CHANNEL_CONTROL,
8873 .handler_count = ARRAY_SIZE(mgmt_handlers),
8874 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008875 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008876};
8877
8878int mgmt_init(void)
8879{
8880 return hci_mgmt_chan_register(&chan);
8881}
8882
8883void mgmt_exit(void)
8884{
8885 hci_mgmt_chan_unregister(&chan);
8886}