blob: f6e510d06becb0f19abd973c7bac79735b2ba710 [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 Holtmannd58cf002021-03-24 15:10:59 +010043#define MGMT_REVISION 20
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,
Marcel Holtmann02431b62021-03-24 15:10:55 +0100111 MGMT_OP_GET_PHY_CONFIGURATION,
112 MGMT_OP_SET_PHY_CONFIGURATION,
Alain Michaud600a8742020-01-07 00:43:17 +0000113 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000114 MGMT_OP_SET_WIDEBAND_SPEECH,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800115 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200116 MGMT_OP_READ_EXP_FEATURES_INFO,
117 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000118 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
119 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200120 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
121 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200122 MGMT_OP_GET_DEVICE_FLAGS,
123 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200124 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200125 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200126 MGMT_OP_REMOVE_ADV_MONITOR,
Daniel Winkler12410572020-12-03 12:12:49 -0800127 MGMT_OP_ADD_EXT_ADV_PARAMS,
128 MGMT_OP_ADD_EXT_ADV_DATA,
Archie Pusakab4a221e2021-01-22 16:36:11 +0800129 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200130};
131
132static const u16 mgmt_events[] = {
133 MGMT_EV_CONTROLLER_ERROR,
134 MGMT_EV_INDEX_ADDED,
135 MGMT_EV_INDEX_REMOVED,
136 MGMT_EV_NEW_SETTINGS,
137 MGMT_EV_CLASS_OF_DEV_CHANGED,
138 MGMT_EV_LOCAL_NAME_CHANGED,
139 MGMT_EV_NEW_LINK_KEY,
140 MGMT_EV_NEW_LONG_TERM_KEY,
141 MGMT_EV_DEVICE_CONNECTED,
142 MGMT_EV_DEVICE_DISCONNECTED,
143 MGMT_EV_CONNECT_FAILED,
144 MGMT_EV_PIN_CODE_REQUEST,
145 MGMT_EV_USER_CONFIRM_REQUEST,
146 MGMT_EV_USER_PASSKEY_REQUEST,
147 MGMT_EV_AUTH_FAILED,
148 MGMT_EV_DEVICE_FOUND,
149 MGMT_EV_DISCOVERING,
150 MGMT_EV_DEVICE_BLOCKED,
151 MGMT_EV_DEVICE_UNBLOCKED,
152 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300153 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800154 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700155 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200156 MGMT_EV_DEVICE_ADDED,
157 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300158 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200159 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200160 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200161 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700164 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700165 MGMT_EV_ADVERTISING_ADDED,
166 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200167 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200168 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200169 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200170 MGMT_EV_DEVICE_FLAGS_CHANGED,
Marcel Holtmann3d34a712021-03-24 15:10:56 +0100171 MGMT_EV_ADV_MONITOR_ADDED,
172 MGMT_EV_ADV_MONITOR_REMOVED,
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -0700173 MGMT_EV_CONTROLLER_SUSPEND,
174 MGMT_EV_CONTROLLER_RESUME,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200175};
176
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700177static const u16 mgmt_untrusted_commands[] = {
178 MGMT_OP_READ_INDEX_LIST,
179 MGMT_OP_READ_INFO,
180 MGMT_OP_READ_UNCONF_INDEX_LIST,
181 MGMT_OP_READ_CONFIG_INFO,
182 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200183 MGMT_OP_READ_EXT_INFO,
Daniel Winkler4d9b9522020-12-03 12:12:52 -0800184 MGMT_OP_READ_CONTROLLER_CAP,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200185 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000186 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200187 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700188};
189
190static const u16 mgmt_untrusted_events[] = {
191 MGMT_EV_INDEX_ADDED,
192 MGMT_EV_INDEX_REMOVED,
193 MGMT_EV_NEW_SETTINGS,
194 MGMT_EV_CLASS_OF_DEV_CHANGED,
195 MGMT_EV_LOCAL_NAME_CHANGED,
196 MGMT_EV_UNCONF_INDEX_ADDED,
197 MGMT_EV_UNCONF_INDEX_REMOVED,
198 MGMT_EV_NEW_CONFIG_OPTIONS,
199 MGMT_EV_EXT_INDEX_ADDED,
200 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200201 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200202 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700203};
204
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800205#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200206
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200207#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
208 "\x00\x00\x00\x00\x00\x00\x00\x00"
209
Johan Hedbergca69b792011-11-11 18:10:00 +0200210/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000211static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200212 MGMT_STATUS_SUCCESS,
213 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
214 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
215 MGMT_STATUS_FAILED, /* Hardware Failure */
216 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
217 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200218 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200219 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
220 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
221 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
222 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
223 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
224 MGMT_STATUS_BUSY, /* Command Disallowed */
225 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
226 MGMT_STATUS_REJECTED, /* Rejected Security */
227 MGMT_STATUS_REJECTED, /* Rejected Personal */
228 MGMT_STATUS_TIMEOUT, /* Host Timeout */
229 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
230 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
231 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
232 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
233 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
234 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
235 MGMT_STATUS_BUSY, /* Repeated Attempts */
236 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
237 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
238 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
239 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
240 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
241 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
242 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
243 MGMT_STATUS_FAILED, /* Unspecified Error */
244 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
245 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
246 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
247 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
248 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
249 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
250 MGMT_STATUS_FAILED, /* Unit Link Key Used */
251 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
252 MGMT_STATUS_TIMEOUT, /* Instant Passed */
253 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
254 MGMT_STATUS_FAILED, /* Transaction Collision */
255 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
256 MGMT_STATUS_REJECTED, /* QoS Rejected */
257 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
258 MGMT_STATUS_REJECTED, /* Insufficient Security */
259 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
260 MGMT_STATUS_BUSY, /* Role Switch Pending */
261 MGMT_STATUS_FAILED, /* Slot Violation */
262 MGMT_STATUS_FAILED, /* Role Switch Failed */
263 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
264 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
265 MGMT_STATUS_BUSY, /* Host Busy Pairing */
266 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
267 MGMT_STATUS_BUSY, /* Controller Busy */
268 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
269 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
270 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
271 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
272 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
273};
274
275static u8 mgmt_status(u8 hci_status)
276{
277 if (hci_status < ARRAY_SIZE(mgmt_status_table))
278 return mgmt_status_table[hci_status];
279
280 return MGMT_STATUS_FAILED;
281}
282
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700283static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
284 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700285{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700286 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
287 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700288}
289
Marcel Holtmann72000df2015-03-16 16:11:21 -0700290static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
291 u16 len, int flag, struct sock *skip_sk)
292{
293 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
294 flag, skip_sk);
295}
296
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200297static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
298 struct sock *skip_sk)
299{
300 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700301 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200302}
303
Johan Hedberg85813a72015-10-21 18:02:59 +0300304static u8 le_addr_type(u8 mgmt_addr_type)
305{
306 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
307 return ADDR_LE_DEV_PUBLIC;
308 else
309 return ADDR_LE_DEV_RANDOM;
310}
311
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200312void mgmt_fill_version_info(void *ver)
313{
314 struct mgmt_rp_read_version *rp = ver;
315
316 rp->version = MGMT_VERSION;
317 rp->revision = cpu_to_le16(MGMT_REVISION);
318}
319
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300320static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
321 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200322{
323 struct mgmt_rp_read_version rp;
324
Marcel Holtmann181d6952020-05-06 09:57:47 +0200325 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200326
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200327 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200328
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200329 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
330 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200331}
332
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300333static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
334 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200335{
336 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700337 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338 size_t rp_size;
339 int i, err;
340
Marcel Holtmann181d6952020-05-06 09:57:47 +0200341 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200342
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700343 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
344 num_commands = ARRAY_SIZE(mgmt_commands);
345 num_events = ARRAY_SIZE(mgmt_events);
346 } else {
347 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
348 num_events = ARRAY_SIZE(mgmt_untrusted_events);
349 }
350
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200351 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
352
353 rp = kmalloc(rp_size, GFP_KERNEL);
354 if (!rp)
355 return -ENOMEM;
356
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700357 rp->num_commands = cpu_to_le16(num_commands);
358 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200359
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700360 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
361 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200362
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700363 for (i = 0; i < num_commands; i++, opcode++)
364 put_unaligned_le16(mgmt_commands[i], opcode);
365
366 for (i = 0; i < num_events; i++, opcode++)
367 put_unaligned_le16(mgmt_events[i], opcode);
368 } else {
369 __le16 *opcode = rp->opcodes;
370
371 for (i = 0; i < num_commands; i++, opcode++)
372 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
373
374 for (i = 0; i < num_events; i++, opcode++)
375 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
376 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200377
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200378 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
379 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200380 kfree(rp);
381
382 return err;
383}
384
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300385static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
386 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200387{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200388 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200389 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200390 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300392 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200393
Marcel Holtmann181d6952020-05-06 09:57:47 +0200394 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200395
396 read_lock(&hci_dev_list_lock);
397
398 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300399 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200400 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700401 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700402 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200403 }
404
Johan Hedberga38528f2011-01-22 06:46:43 +0200405 rp_len = sizeof(*rp) + (2 * count);
406 rp = kmalloc(rp_len, GFP_ATOMIC);
407 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100408 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200409 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100410 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200411
Johan Hedberg476e44c2012-10-19 20:10:46 +0300412 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200413 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700414 if (hci_dev_test_flag(d, HCI_SETUP) ||
415 hci_dev_test_flag(d, HCI_CONFIG) ||
416 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200417 continue;
418
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200419 /* Devices marked as raw-only are neither configured
420 * nor unconfigured controllers.
421 */
422 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700423 continue;
424
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200425 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700426 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700427 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200428 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700429 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200430 }
431
Johan Hedberg476e44c2012-10-19 20:10:46 +0300432 rp->num_controllers = cpu_to_le16(count);
433 rp_len = sizeof(*rp) + (2 * count);
434
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200435 read_unlock(&hci_dev_list_lock);
436
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200437 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
438 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200439
Johan Hedberga38528f2011-01-22 06:46:43 +0200440 kfree(rp);
441
442 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200443}
444
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200445static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
446 void *data, u16 data_len)
447{
448 struct mgmt_rp_read_unconf_index_list *rp;
449 struct hci_dev *d;
450 size_t rp_len;
451 u16 count;
452 int err;
453
Marcel Holtmann181d6952020-05-06 09:57:47 +0200454 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200455
456 read_lock(&hci_dev_list_lock);
457
458 count = 0;
459 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200460 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700461 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200462 count++;
463 }
464
465 rp_len = sizeof(*rp) + (2 * count);
466 rp = kmalloc(rp_len, GFP_ATOMIC);
467 if (!rp) {
468 read_unlock(&hci_dev_list_lock);
469 return -ENOMEM;
470 }
471
472 count = 0;
473 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700474 if (hci_dev_test_flag(d, HCI_SETUP) ||
475 hci_dev_test_flag(d, HCI_CONFIG) ||
476 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200477 continue;
478
479 /* Devices marked as raw-only are neither configured
480 * nor unconfigured controllers.
481 */
482 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
483 continue;
484
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200485 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700486 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200487 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200488 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200489 }
490 }
491
492 rp->num_controllers = cpu_to_le16(count);
493 rp_len = sizeof(*rp) + (2 * count);
494
495 read_unlock(&hci_dev_list_lock);
496
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200497 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
498 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200499
500 kfree(rp);
501
502 return err;
503}
504
Marcel Holtmann96f14742015-03-14 19:27:57 -0700505static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
506 void *data, u16 data_len)
507{
508 struct mgmt_rp_read_ext_index_list *rp;
509 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700510 u16 count;
511 int err;
512
Marcel Holtmann181d6952020-05-06 09:57:47 +0200513 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700514
515 read_lock(&hci_dev_list_lock);
516
517 count = 0;
518 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200519 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700520 count++;
521 }
522
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600523 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700524 if (!rp) {
525 read_unlock(&hci_dev_list_lock);
526 return -ENOMEM;
527 }
528
529 count = 0;
530 list_for_each_entry(d, &hci_dev_list, list) {
531 if (hci_dev_test_flag(d, HCI_SETUP) ||
532 hci_dev_test_flag(d, HCI_CONFIG) ||
533 hci_dev_test_flag(d, HCI_USER_CHANNEL))
534 continue;
535
536 /* Devices marked as raw-only are neither configured
537 * nor unconfigured controllers.
538 */
539 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
540 continue;
541
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200542 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700543 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
544 rp->entry[count].type = 0x01;
545 else
546 rp->entry[count].type = 0x00;
547 } else if (d->dev_type == HCI_AMP) {
548 rp->entry[count].type = 0x02;
549 } else {
550 continue;
551 }
552
553 rp->entry[count].bus = d->bus;
554 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200555 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700556 }
557
558 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700559
560 read_unlock(&hci_dev_list_lock);
561
562 /* If this command is called at least once, then all the
563 * default index and unconfigured index events are disabled
564 * and from now on only extended index events are used.
565 */
566 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
567 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
568 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
569
570 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600571 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
572 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700573
574 kfree(rp);
575
576 return err;
577}
578
Marcel Holtmanndbece372014-07-04 18:11:55 +0200579static bool is_configured(struct hci_dev *hdev)
580{
581 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700582 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200583 return false;
584
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800585 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
586 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200587 !bacmp(&hdev->public_addr, BDADDR_ANY))
588 return false;
589
590 return true;
591}
592
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200593static __le32 get_missing_options(struct hci_dev *hdev)
594{
595 u32 options = 0;
596
Marcel Holtmanndbece372014-07-04 18:11:55 +0200597 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700598 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 options |= MGMT_OPTION_EXTERNAL_CONFIG;
600
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800601 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
602 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 !bacmp(&hdev->public_addr, BDADDR_ANY))
604 options |= MGMT_OPTION_PUBLIC_ADDRESS;
605
606 return cpu_to_le32(options);
607}
608
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200609static int new_options(struct hci_dev *hdev, struct sock *skip)
610{
611 __le32 options = get_missing_options(hdev);
612
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200613 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
614 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200615}
616
Marcel Holtmanndbece372014-07-04 18:11:55 +0200617static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
618{
619 __le32 options = get_missing_options(hdev);
620
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200621 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
622 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200623}
624
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200625static int read_config_info(struct sock *sk, struct hci_dev *hdev,
626 void *data, u16 data_len)
627{
628 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200629 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200630
Marcel Holtmann181d6952020-05-06 09:57:47 +0200631 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200632
633 hci_dev_lock(hdev);
634
635 memset(&rp, 0, sizeof(rp));
636 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200637
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200638 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
639 options |= MGMT_OPTION_EXTERNAL_CONFIG;
640
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200641 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200642 options |= MGMT_OPTION_PUBLIC_ADDRESS;
643
644 rp.supported_options = cpu_to_le32(options);
645 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200646
647 hci_dev_unlock(hdev);
648
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200649 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
650 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200651}
652
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530653static u32 get_supported_phys(struct hci_dev *hdev)
654{
655 u32 supported_phys = 0;
656
657 if (lmp_bredr_capable(hdev)) {
658 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
659
660 if (hdev->features[0][0] & LMP_3SLOT)
661 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
662
663 if (hdev->features[0][0] & LMP_5SLOT)
664 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
665
666 if (lmp_edr_2m_capable(hdev)) {
667 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
668
669 if (lmp_edr_3slot_capable(hdev))
670 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
671
672 if (lmp_edr_5slot_capable(hdev))
673 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
674
675 if (lmp_edr_3m_capable(hdev)) {
676 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
677
678 if (lmp_edr_3slot_capable(hdev))
679 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
680
681 if (lmp_edr_5slot_capable(hdev))
682 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
683 }
684 }
685 }
686
687 if (lmp_le_capable(hdev)) {
688 supported_phys |= MGMT_PHY_LE_1M_TX;
689 supported_phys |= MGMT_PHY_LE_1M_RX;
690
691 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
692 supported_phys |= MGMT_PHY_LE_2M_TX;
693 supported_phys |= MGMT_PHY_LE_2M_RX;
694 }
695
696 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
697 supported_phys |= MGMT_PHY_LE_CODED_TX;
698 supported_phys |= MGMT_PHY_LE_CODED_RX;
699 }
700 }
701
702 return supported_phys;
703}
704
705static u32 get_selected_phys(struct hci_dev *hdev)
706{
707 u32 selected_phys = 0;
708
709 if (lmp_bredr_capable(hdev)) {
710 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
711
712 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
713 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
714
715 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
716 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
717
718 if (lmp_edr_2m_capable(hdev)) {
719 if (!(hdev->pkt_type & HCI_2DH1))
720 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
721
722 if (lmp_edr_3slot_capable(hdev) &&
723 !(hdev->pkt_type & HCI_2DH3))
724 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
725
726 if (lmp_edr_5slot_capable(hdev) &&
727 !(hdev->pkt_type & HCI_2DH5))
728 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
729
730 if (lmp_edr_3m_capable(hdev)) {
731 if (!(hdev->pkt_type & HCI_3DH1))
732 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
733
734 if (lmp_edr_3slot_capable(hdev) &&
735 !(hdev->pkt_type & HCI_3DH3))
736 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
737
738 if (lmp_edr_5slot_capable(hdev) &&
739 !(hdev->pkt_type & HCI_3DH5))
740 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
741 }
742 }
743 }
744
745 if (lmp_le_capable(hdev)) {
746 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
747 selected_phys |= MGMT_PHY_LE_1M_TX;
748
749 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
750 selected_phys |= MGMT_PHY_LE_1M_RX;
751
752 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
753 selected_phys |= MGMT_PHY_LE_2M_TX;
754
755 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
756 selected_phys |= MGMT_PHY_LE_2M_RX;
757
758 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
759 selected_phys |= MGMT_PHY_LE_CODED_TX;
760
761 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
762 selected_phys |= MGMT_PHY_LE_CODED_RX;
763 }
764
765 return selected_phys;
766}
767
768static u32 get_configurable_phys(struct hci_dev *hdev)
769{
770 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
771 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
772}
773
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200774static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200775{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200776 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200777
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200778 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300779 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800780 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300781 settings |= MGMT_SETTING_CONNECTABLE;
782 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200783
Andre Guedesed3fa312012-07-24 15:03:46 -0300784 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500785 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
786 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 settings |= MGMT_SETTING_BREDR;
788 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700789
790 if (lmp_ssp_capable(hdev)) {
791 settings |= MGMT_SETTING_SSP;
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -0700792 if (IS_ENABLED(CONFIG_BT_HS))
793 settings |= MGMT_SETTING_HS;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700794 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800795
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800796 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800797 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000798
Alain Michaud00bce3f2020-03-05 16:14:59 +0000799 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000800 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000801 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700802 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100803
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300804 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200805 settings |= MGMT_SETTING_LE;
Johan Hedberga3209692014-05-26 11:23:35 +0300806 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200807 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800808 settings |= MGMT_SETTING_STATIC_ADDRESS;
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +0530809
810 /* When the experimental feature for LL Privacy support is
811 * enabled, then advertising is no longer supported.
812 */
813 if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
814 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300815 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200816
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200817 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
818 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200819 settings |= MGMT_SETTING_CONFIGURATION;
820
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530821 settings |= MGMT_SETTING_PHY_CONFIGURATION;
822
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200823 return settings;
824}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200825
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200826static u32 get_current_settings(struct hci_dev *hdev)
827{
828 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200829
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200830 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100831 settings |= MGMT_SETTING_POWERED;
832
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700833 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200834 settings |= MGMT_SETTING_CONNECTABLE;
835
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700836 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500837 settings |= MGMT_SETTING_FAST_CONNECTABLE;
838
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700839 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200840 settings |= MGMT_SETTING_DISCOVERABLE;
841
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700842 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300843 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200844
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700845 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846 settings |= MGMT_SETTING_BREDR;
847
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700848 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200849 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200850
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700851 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200852 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700854 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200855 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200856
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700857 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200858 settings |= MGMT_SETTING_HS;
859
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700860 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300861 settings |= MGMT_SETTING_ADVERTISING;
862
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700863 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800864 settings |= MGMT_SETTING_SECURE_CONN;
865
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700866 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800867 settings |= MGMT_SETTING_DEBUG_KEYS;
868
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700869 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200870 settings |= MGMT_SETTING_PRIVACY;
871
Marcel Holtmann93690c22015-03-06 10:11:21 -0800872 /* The current setting for static address has two purposes. The
873 * first is to indicate if the static address will be used and
874 * the second is to indicate if it is actually set.
875 *
876 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700877 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800878 * address is actually used decides if the flag is set or not.
879 *
880 * For single mode LE only controllers and dual-mode controllers
881 * with BR/EDR disabled, the existence of the static address will
882 * be evaluated.
883 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700884 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700885 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800886 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
887 if (bacmp(&hdev->static_addr, BDADDR_ANY))
888 settings |= MGMT_SETTING_STATIC_ADDRESS;
889 }
890
Alain Michaud00bce3f2020-03-05 16:14:59 +0000891 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
892 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
893
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200894 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200895}
896
Johan Hedberg333ae952015-03-17 13:48:47 +0200897static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
898{
899 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
900}
901
Johan Hedberg333ae952015-03-17 13:48:47 +0200902static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
903 struct hci_dev *hdev,
904 const void *data)
905{
906 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
907}
908
Johan Hedbergf2252572015-11-18 12:49:20 +0200909u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300910{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200911 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300912
913 /* If there's a pending mgmt command the flags will not yet have
914 * their final values, so check for this first.
915 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200916 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300917 if (cmd) {
918 struct mgmt_mode *cp = cmd->param;
919 if (cp->val == 0x01)
920 return LE_AD_GENERAL;
921 else if (cp->val == 0x02)
922 return LE_AD_LIMITED;
923 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700924 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300925 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700926 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300927 return LE_AD_GENERAL;
928 }
929
930 return 0;
931}
932
Johan Hedbergf2252572015-11-18 12:49:20 +0200933bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700934{
935 struct mgmt_pending_cmd *cmd;
936
937 /* If there's a pending mgmt command the flag will not yet have
938 * it's final value, so check for this first.
939 */
940 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
941 if (cmd) {
942 struct mgmt_mode *cp = cmd->param;
943
944 return cp->val;
945 }
946
947 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
948}
949
Johan Hedberg7d785252011-12-15 00:47:39 +0200950static void service_cache_off(struct work_struct *work)
951{
952 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300953 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500954 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200955
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700956 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200957 return;
958
Johan Hedberg890ea892013-03-15 17:06:52 -0500959 hci_req_init(&req, hdev);
960
Johan Hedberg7d785252011-12-15 00:47:39 +0200961 hci_dev_lock(hdev);
962
Johan Hedbergb1a89172015-11-25 16:15:42 +0200963 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200964 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200965
966 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500967
968 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200969}
970
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200971static void rpa_expired(struct work_struct *work)
972{
973 struct hci_dev *hdev = container_of(work, struct hci_dev,
974 rpa_expired.work);
975 struct hci_request req;
976
Marcel Holtmann181d6952020-05-06 09:57:47 +0200977 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200978
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700979 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200980
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700981 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200982 return;
983
984 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200985 * controller happens in the hci_req_enable_advertising()
986 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200987 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200988 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530989 if (ext_adv_capable(hdev))
990 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
991 else
992 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200993 hci_req_run(&req, NULL);
994}
995
Johan Hedberg6a919082012-02-28 06:17:26 +0200996static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200997{
Marcel Holtmann238be782015-03-13 02:11:06 -0700998 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200999 return;
1000
Johan Hedberg4f87da82012-03-02 19:55:56 +02001001 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001002 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001003
Johan Hedberg4f87da82012-03-02 19:55:56 +02001004 /* Non-mgmt controlled devices get this bit set
1005 * implicitly so that pairing works for them, however
1006 * for mgmt we require user-space to explicitly enable
1007 * it
1008 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001009 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001010}
1011
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001012static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001013 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001014{
1015 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001016
Marcel Holtmann181d6952020-05-06 09:57:47 +02001017 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001018
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001019 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001020
Johan Hedberg03811012010-12-08 00:21:06 +02001021 memset(&rp, 0, sizeof(rp));
1022
Johan Hedberg03811012010-12-08 00:21:06 +02001023 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001024
1025 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001026 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001027
1028 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1029 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1030
1031 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001032
1033 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001034 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001035
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001036 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001037
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001038 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1039 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001040}
1041
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001042static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1043{
1044 u16 eir_len = 0;
1045 size_t name_len;
1046
1047 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1048 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1049 hdev->dev_class, 3);
1050
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001051 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1052 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1053 hdev->appearance);
1054
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001055 name_len = strlen(hdev->dev_name);
1056 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1057 hdev->dev_name, name_len);
1058
1059 name_len = strlen(hdev->short_name);
1060 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1061 hdev->short_name, name_len);
1062
1063 return eir_len;
1064}
1065
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001066static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1067 void *data, u16 data_len)
1068{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001069 char buf[512];
1070 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001071 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001072
Marcel Holtmann181d6952020-05-06 09:57:47 +02001073 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001074
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001075 memset(&buf, 0, sizeof(buf));
1076
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001077 hci_dev_lock(hdev);
1078
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001079 bacpy(&rp->bdaddr, &hdev->bdaddr);
1080
1081 rp->version = hdev->hci_ver;
1082 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1083
1084 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1085 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001086
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001087
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001088 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001089 rp->eir_len = cpu_to_le16(eir_len);
1090
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001091 hci_dev_unlock(hdev);
1092
1093 /* If this command is called at least once, then the events
1094 * for class of device and local name changes are disabled
1095 * and only the new extended controller information event
1096 * is used.
1097 */
1098 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1099 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1100 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1101
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001102 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1103 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001104}
1105
1106static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1107{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001108 char buf[512];
1109 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1110 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001111
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001112 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001113
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001114 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1115 ev->eir_len = cpu_to_le16(eir_len);
1116
1117 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1118 sizeof(*ev) + eir_len,
1119 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001120}
1121
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001122static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001123{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001124 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001125
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001126 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1127 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001128}
1129
Marcel Holtmann1904a852015-01-11 13:50:44 -08001130static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001131{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001132 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001133
Johan Hedberga3172b72014-02-28 09:33:44 +02001134 if (hci_conn_count(hdev) == 0) {
1135 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001136 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001137 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001138}
1139
Johan Hedbergf2252572015-11-18 12:49:20 +02001140void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001141{
1142 struct mgmt_ev_advertising_added ev;
1143
1144 ev.instance = instance;
1145
1146 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1147}
1148
Johan Hedbergf2252572015-11-18 12:49:20 +02001149void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1150 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001151{
1152 struct mgmt_ev_advertising_removed ev;
1153
1154 ev.instance = instance;
1155
1156 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1157}
1158
Florian Grandel7816b822015-06-18 03:16:45 +02001159static void cancel_adv_timeout(struct hci_dev *hdev)
1160{
1161 if (hdev->adv_instance_timeout) {
1162 hdev->adv_instance_timeout = 0;
1163 cancel_delayed_work(&hdev->adv_instance_expire);
1164 }
1165}
1166
Johan Hedberg8b064a32014-02-24 14:52:22 +02001167static int clean_up_hci_state(struct hci_dev *hdev)
1168{
1169 struct hci_request req;
1170 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001171 bool discov_stopped;
1172 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001173
1174 hci_req_init(&req, hdev);
1175
1176 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1177 test_bit(HCI_PSCAN, &hdev->flags)) {
1178 u8 scan = 0x00;
1179 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1180 }
1181
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001182 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001183
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001184 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001185 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001187 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001188
1189 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001190 /* 0x15 == Terminated due to Power Off */
1191 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001192 }
1193
Johan Hedberg23a48092014-07-08 16:05:06 +03001194 err = hci_req_run(&req, clean_up_hci_complete);
1195 if (!err && discov_stopped)
1196 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1197
1198 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001199}
1200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001202 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001203{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001204 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001205 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001206 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Marcel Holtmann181d6952020-05-06 09:57:47 +02001208 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209
Johan Hedberga7e80f22013-01-09 16:05:19 +02001210 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001211 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1212 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001214 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215
Johan Hedberg333ae952015-03-17 13:48:47 +02001216 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001217 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1218 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001219 goto failed;
1220 }
1221
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001222 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001223 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001224 goto failed;
1225 }
1226
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001227 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1228 if (!cmd) {
1229 err = -ENOMEM;
1230 goto failed;
1231 }
1232
Johan Hedberg8b064a32014-02-24 14:52:22 +02001233 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001234 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001235 err = 0;
1236 } else {
1237 /* Disconnect connections, stop scans, etc */
1238 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001239 if (!err)
1240 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1241 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001242
Johan Hedberg8b064a32014-02-24 14:52:22 +02001243 /* ENODATA means there were no HCI commands queued */
1244 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001245 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001246 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1247 err = 0;
1248 }
1249 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001250
1251failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001252 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001253 return err;
1254}
1255
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001256static int new_settings(struct hci_dev *hdev, struct sock *skip)
1257{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001258 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001259
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001260 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1261 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001262}
1263
Johan Hedberg91a668b2014-07-09 13:28:26 +03001264int mgmt_new_settings(struct hci_dev *hdev)
1265{
1266 return new_settings(hdev, NULL);
1267}
1268
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001269struct cmd_lookup {
1270 struct sock *sk;
1271 struct hci_dev *hdev;
1272 u8 mgmt_status;
1273};
1274
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001275static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001276{
1277 struct cmd_lookup *match = data;
1278
1279 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1280
1281 list_del(&cmd->list);
1282
1283 if (match->sk == NULL) {
1284 match->sk = cmd->sk;
1285 sock_hold(match->sk);
1286 }
1287
1288 mgmt_pending_free(cmd);
1289}
1290
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001291static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001292{
1293 u8 *status = data;
1294
Johan Hedberga69e8372015-03-06 21:08:53 +02001295 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001296 mgmt_pending_remove(cmd);
1297}
1298
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001299static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001300{
1301 if (cmd->cmd_complete) {
1302 u8 *status = data;
1303
1304 cmd->cmd_complete(cmd, *status);
1305 mgmt_pending_remove(cmd);
1306
1307 return;
1308 }
1309
1310 cmd_status_rsp(cmd, data);
1311}
1312
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001313static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001314{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001315 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1316 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001317}
1318
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001319static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001320{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001321 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1322 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001323}
1324
Johan Hedberge6fe7982013-10-02 15:45:22 +03001325static u8 mgmt_bredr_support(struct hci_dev *hdev)
1326{
1327 if (!lmp_bredr_capable(hdev))
1328 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001329 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001330 return MGMT_STATUS_REJECTED;
1331 else
1332 return MGMT_STATUS_SUCCESS;
1333}
1334
1335static u8 mgmt_le_support(struct hci_dev *hdev)
1336{
1337 if (!lmp_le_capable(hdev))
1338 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001339 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001340 return MGMT_STATUS_REJECTED;
1341 else
1342 return MGMT_STATUS_SUCCESS;
1343}
1344
Johan Hedbergaed1a882015-11-22 17:24:44 +03001345void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001346{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348
Marcel Holtmann181d6952020-05-06 09:57:47 +02001349 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001350
1351 hci_dev_lock(hdev);
1352
Johan Hedberg333ae952015-03-17 13:48:47 +02001353 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001354 if (!cmd)
1355 goto unlock;
1356
1357 if (status) {
1358 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001359 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001360 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001361 goto remove_cmd;
1362 }
1363
Johan Hedbergaed1a882015-11-22 17:24:44 +03001364 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1365 hdev->discov_timeout > 0) {
1366 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1367 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001368 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001369
1370 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001371 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001372
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001373remove_cmd:
1374 mgmt_pending_remove(cmd);
1375
1376unlock:
1377 hci_dev_unlock(hdev);
1378}
1379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001380static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001381 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001382{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001383 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001384 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001385 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001386 int err;
1387
Marcel Holtmann181d6952020-05-06 09:57:47 +02001388 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001389
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001390 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1391 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001392 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1393 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001394
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001395 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001396 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1397 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001398
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001399 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001400
1401 /* Disabling discoverable requires that no timeout is set,
1402 * and enabling limited discoverable requires a timeout.
1403 */
1404 if ((cp->val == 0x00 && timeout > 0) ||
1405 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001406 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1407 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001409 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001410
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001411 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001412 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1413 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001414 goto failed;
1415 }
1416
Johan Hedberg333ae952015-03-17 13:48:47 +02001417 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1418 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001419 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1420 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001421 goto failed;
1422 }
1423
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001424 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001425 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1426 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001427 goto failed;
1428 }
1429
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001430 if (hdev->advertising_paused) {
1431 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1432 MGMT_STATUS_BUSY);
1433 goto failed;
1434 }
1435
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001436 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001437 bool changed = false;
1438
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001439 /* Setting limited discoverable when powered off is
1440 * not a valid operation since it requires a timeout
1441 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1442 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001443 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001444 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001445 changed = true;
1446 }
1447
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001448 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001449 if (err < 0)
1450 goto failed;
1451
1452 if (changed)
1453 err = new_settings(hdev, sk);
1454
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001455 goto failed;
1456 }
1457
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001458 /* If the current mode is the same, then just update the timeout
1459 * value with the new value. And if only the timeout gets updated,
1460 * then no need for any HCI transactions.
1461 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001462 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1463 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1464 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001465 cancel_delayed_work(&hdev->discov_off);
1466 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001467
Marcel Holtmann36261542013-10-15 08:28:51 -07001468 if (cp->val && hdev->discov_timeout > 0) {
1469 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001470 queue_delayed_work(hdev->req_workqueue,
1471 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001472 }
1473
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001474 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001475 goto failed;
1476 }
1477
1478 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1479 if (!cmd) {
1480 err = -ENOMEM;
1481 goto failed;
1482 }
1483
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001484 /* Cancel any potential discoverable timeout that might be
1485 * still active and store new timeout value. The arming of
1486 * the timeout happens in the complete handler.
1487 */
1488 cancel_delayed_work(&hdev->discov_off);
1489 hdev->discov_timeout = timeout;
1490
Johan Hedbergaed1a882015-11-22 17:24:44 +03001491 if (cp->val)
1492 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1493 else
1494 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1495
Johan Hedbergb456f872013-10-19 23:38:22 +03001496 /* Limited discoverable mode */
1497 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001498 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001499 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001500 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001501
Johan Hedbergaed1a882015-11-22 17:24:44 +03001502 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1503 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001504
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001506 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001507 return err;
1508}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001509
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001510void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001511{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001512 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001513
Marcel Holtmann181d6952020-05-06 09:57:47 +02001514 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001515
1516 hci_dev_lock(hdev);
1517
Johan Hedberg333ae952015-03-17 13:48:47 +02001518 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001519 if (!cmd)
1520 goto unlock;
1521
Johan Hedberg37438c12013-10-14 16:20:05 +03001522 if (status) {
1523 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001524 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001525 goto remove_cmd;
1526 }
1527
Johan Hedberg2b76f452013-03-15 17:07:04 -05001528 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001529 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001530
Johan Hedberg37438c12013-10-14 16:20:05 +03001531remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001532 mgmt_pending_remove(cmd);
1533
1534unlock:
1535 hci_dev_unlock(hdev);
1536}
1537
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001538static int set_connectable_update_settings(struct hci_dev *hdev,
1539 struct sock *sk, u8 val)
1540{
1541 bool changed = false;
1542 int err;
1543
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001544 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001545 changed = true;
1546
1547 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001548 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001549 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001550 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1551 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001552 }
1553
1554 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1555 if (err < 0)
1556 return err;
1557
Johan Hedberg562064e2014-07-08 16:35:34 +03001558 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001559 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001560 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001561 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001562 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001563
1564 return 0;
1565}
1566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001567static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001568 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001570 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001571 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001572 int err;
1573
Marcel Holtmann181d6952020-05-06 09:57:47 +02001574 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001575
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001576 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1577 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001578 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1579 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001580
Johan Hedberga7e80f22013-01-09 16:05:19 +02001581 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001582 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1583 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001585 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001586
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001587 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001588 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001589 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001590 }
1591
Johan Hedberg333ae952015-03-17 13:48:47 +02001592 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1593 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001594 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1595 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001596 goto failed;
1597 }
1598
Johan Hedberg73f22f62010-12-29 16:00:25 +02001599 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1600 if (!cmd) {
1601 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001602 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001603 }
1604
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001605 if (cp->val) {
1606 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1607 } else {
1608 if (hdev->discov_timeout > 0)
1609 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001610
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001611 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1612 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1613 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001614 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001615
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001616 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1617 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001618
1619failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001620 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001621 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001622}
1623
Johan Hedbergb2939472014-07-30 09:22:23 +03001624static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001625 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001627 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001628 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001629 int err;
1630
Marcel Holtmann181d6952020-05-06 09:57:47 +02001631 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001632
Johan Hedberga7e80f22013-01-09 16:05:19 +02001633 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001634 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1635 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001636
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001637 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001638
1639 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001640 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001641 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001642 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001643
Johan Hedbergb2939472014-07-30 09:22:23 +03001644 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001645 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001646 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001647
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001648 if (changed) {
1649 /* In limited privacy mode the change of bondable mode
1650 * may affect the local advertising address.
1651 */
1652 if (hdev_is_powered(hdev) &&
1653 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1654 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1655 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1656 queue_work(hdev->req_workqueue,
1657 &hdev->discoverable_update);
1658
Marcel Holtmann55594352013-10-06 16:11:57 -07001659 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001660 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001661
Marcel Holtmann55594352013-10-06 16:11:57 -07001662unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001663 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001664 return err;
1665}
1666
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001667static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1668 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001669{
1670 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001671 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001672 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001673 int err;
1674
Marcel Holtmann181d6952020-05-06 09:57:47 +02001675 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001676
Johan Hedberge6fe7982013-10-02 15:45:22 +03001677 status = mgmt_bredr_support(hdev);
1678 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001679 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1680 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001681
Johan Hedberga7e80f22013-01-09 16:05:19 +02001682 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001683 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1684 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001685
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001686 hci_dev_lock(hdev);
1687
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001688 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001689 bool changed = false;
1690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001691 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001692 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001693 changed = true;
1694 }
1695
1696 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1697 if (err < 0)
1698 goto failed;
1699
1700 if (changed)
1701 err = new_settings(hdev, sk);
1702
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001703 goto failed;
1704 }
1705
Johan Hedberg333ae952015-03-17 13:48:47 +02001706 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001707 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1708 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001709 goto failed;
1710 }
1711
1712 val = !!cp->val;
1713
1714 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1715 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1716 goto failed;
1717 }
1718
1719 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1720 if (!cmd) {
1721 err = -ENOMEM;
1722 goto failed;
1723 }
1724
1725 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1726 if (err < 0) {
1727 mgmt_pending_remove(cmd);
1728 goto failed;
1729 }
1730
1731failed:
1732 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001733 return err;
1734}
1735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001737{
1738 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001739 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001740 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001741 int err;
1742
Marcel Holtmann181d6952020-05-06 09:57:47 +02001743 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001744
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001745 status = mgmt_bredr_support(hdev);
1746 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001747 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001748
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001749 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001750 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1751 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001752
Johan Hedberga7e80f22013-01-09 16:05:19 +02001753 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001754 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001756
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001757 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001758
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001759 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001760 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001761
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001762 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001763 changed = !hci_dev_test_and_set_flag(hdev,
1764 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001765 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001766 changed = hci_dev_test_and_clear_flag(hdev,
1767 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001768 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001769 changed = hci_dev_test_and_clear_flag(hdev,
1770 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001771 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001772 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001773 }
1774
1775 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1776 if (err < 0)
1777 goto failed;
1778
1779 if (changed)
1780 err = new_settings(hdev, sk);
1781
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001782 goto failed;
1783 }
1784
Johan Hedberg333ae952015-03-17 13:48:47 +02001785 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001786 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1787 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001788 goto failed;
1789 }
1790
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001791 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001792 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1793 goto failed;
1794 }
1795
1796 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1797 if (!cmd) {
1798 err = -ENOMEM;
1799 goto failed;
1800 }
1801
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001802 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001803 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1804 sizeof(cp->val), &cp->val);
1805
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001806 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001807 if (err < 0) {
1808 mgmt_pending_remove(cmd);
1809 goto failed;
1810 }
1811
1812failed:
1813 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001814 return err;
1815}
1816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001818{
1819 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001820 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001821 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001822 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001823
Marcel Holtmann181d6952020-05-06 09:57:47 +02001824 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001825
Luiz Augusto von Dentzb560a202020-08-06 11:17:14 -07001826 if (!IS_ENABLED(CONFIG_BT_HS))
1827 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1828 MGMT_STATUS_NOT_SUPPORTED);
1829
Johan Hedberge6fe7982013-10-02 15:45:22 +03001830 status = mgmt_bredr_support(hdev);
1831 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001832 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001833
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001834 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001835 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1836 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001837
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001838 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001839 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1840 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001841
Johan Hedberga7e80f22013-01-09 16:05:19 +02001842 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001843 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1844 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001845
Marcel Holtmannee392692013-10-01 22:59:23 -07001846 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001847
Johan Hedberg333ae952015-03-17 13:48:47 +02001848 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001849 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1850 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001851 goto unlock;
1852 }
1853
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001854 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001855 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001856 } else {
1857 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001858 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1859 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001860 goto unlock;
1861 }
1862
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001863 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001864 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001865
1866 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1867 if (err < 0)
1868 goto unlock;
1869
1870 if (changed)
1871 err = new_settings(hdev, sk);
1872
1873unlock:
1874 hci_dev_unlock(hdev);
1875 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001876}
1877
Marcel Holtmann1904a852015-01-11 13:50:44 -08001878static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001879{
1880 struct cmd_lookup match = { NULL, hdev };
1881
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301882 hci_dev_lock(hdev);
1883
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001884 if (status) {
1885 u8 mgmt_err = mgmt_status(status);
1886
1887 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1888 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301889 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001890 }
1891
1892 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1893
1894 new_settings(hdev, match.sk);
1895
1896 if (match.sk)
1897 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001898
1899 /* Make sure the controller has a good default for
1900 * advertising data. Restrict the update to when LE
1901 * has actually been enabled. During power on, the
1902 * update in powered_update_hci will take care of it.
1903 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001904 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001905 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001906 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301907 if (ext_adv_capable(hdev)) {
1908 int err;
1909
1910 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1911 if (!err)
1912 __hci_req_update_scan_rsp_data(&req, 0x00);
1913 } else {
1914 __hci_req_update_adv_data(&req, 0x00);
1915 __hci_req_update_scan_rsp_data(&req, 0x00);
1916 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001917 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001918 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001919 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301920
1921unlock:
1922 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001923}
1924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001925static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001926{
1927 struct mgmt_mode *cp = data;
1928 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001929 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001930 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001931 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001932 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001933
Marcel Holtmann181d6952020-05-06 09:57:47 +02001934 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001935
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001936 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001937 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1938 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001939
Johan Hedberga7e80f22013-01-09 16:05:19 +02001940 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001941 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1942 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001943
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001944 /* Bluetooth single mode LE only controllers or dual-mode
1945 * controllers configured as LE only devices, do not allow
1946 * switching LE off. These have either LE enabled explicitly
1947 * or BR/EDR has been previously switched off.
1948 *
1949 * When trying to enable an already enabled LE, then gracefully
1950 * send a positive response. Trying to disable it however will
1951 * result into rejection.
1952 */
1953 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1954 if (cp->val == 0x01)
1955 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1956
Johan Hedberga69e8372015-03-06 21:08:53 +02001957 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1958 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001959 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001960
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001961 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962
1963 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001964 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001965
Florian Grandel847818d2015-06-18 03:16:46 +02001966 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001967 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001968
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001969 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970 bool changed = false;
1971
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001972 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001973 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001974 changed = true;
1975 }
1976
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001977 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001978 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001979 changed = true;
1980 }
1981
Johan Hedberg06199cf2012-02-22 16:37:11 +02001982 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1983 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001984 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001985
1986 if (changed)
1987 err = new_settings(hdev, sk);
1988
Johan Hedberg1de028c2012-02-29 19:55:35 -08001989 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001990 }
1991
Johan Hedberg333ae952015-03-17 13:48:47 +02001992 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1993 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001994 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1995 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001996 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001997 }
1998
1999 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2000 if (!cmd) {
2001 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002002 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002003 }
2004
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002005 hci_req_init(&req, hdev);
2006
Johan Hedberg06199cf2012-02-22 16:37:11 +02002007 memset(&hci_cp, 0, sizeof(hci_cp));
2008
2009 if (val) {
2010 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002011 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002012 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002013 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002014 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05302015
2016 if (ext_adv_capable(hdev))
2017 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002018 }
2019
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002020 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2021 &hci_cp);
2022
2023 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302024 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002025 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002026
Johan Hedberg1de028c2012-02-29 19:55:35 -08002027unlock:
2028 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002029 return err;
2030}
2031
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002032/* This is a helper function to test for pending mgmt commands that can
2033 * cause CoD or EIR HCI commands. We can only allow one such pending
2034 * mgmt command at a time since otherwise we cannot easily track what
2035 * the current values are, will be, and based on that calculate if a new
2036 * HCI command needs to be sent and if yes with what value.
2037 */
2038static bool pending_eir_or_class(struct hci_dev *hdev)
2039{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002040 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002041
2042 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2043 switch (cmd->opcode) {
2044 case MGMT_OP_ADD_UUID:
2045 case MGMT_OP_REMOVE_UUID:
2046 case MGMT_OP_SET_DEV_CLASS:
2047 case MGMT_OP_SET_POWERED:
2048 return true;
2049 }
2050 }
2051
2052 return false;
2053}
2054
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002055static const u8 bluetooth_base_uuid[] = {
2056 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2057 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2058};
2059
2060static u8 get_uuid_size(const u8 *uuid)
2061{
2062 u32 val;
2063
2064 if (memcmp(uuid, bluetooth_base_uuid, 12))
2065 return 128;
2066
2067 val = get_unaligned_le32(&uuid[12]);
2068 if (val > 0xffff)
2069 return 32;
2070
2071 return 16;
2072}
2073
Johan Hedberg92da6092013-03-15 17:06:55 -05002074static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2075{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002076 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002077
2078 hci_dev_lock(hdev);
2079
Johan Hedberg333ae952015-03-17 13:48:47 +02002080 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002081 if (!cmd)
2082 goto unlock;
2083
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002084 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2085 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002086
2087 mgmt_pending_remove(cmd);
2088
2089unlock:
2090 hci_dev_unlock(hdev);
2091}
2092
Marcel Holtmann1904a852015-01-11 13:50:44 -08002093static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002094{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002095 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002096
2097 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2098}
2099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002101{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002102 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002103 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002104 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002105 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002106 int err;
2107
Marcel Holtmann181d6952020-05-06 09:57:47 +02002108 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002110 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002111
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002112 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002113 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2114 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002115 goto failed;
2116 }
2117
Andre Guedes92c4c202012-06-07 19:05:44 -03002118 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119 if (!uuid) {
2120 err = -ENOMEM;
2121 goto failed;
2122 }
2123
2124 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002125 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002126 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127
Johan Hedbergde66aa62013-01-27 00:31:27 +02002128 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129
Johan Hedberg890ea892013-03-15 17:06:52 -05002130 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002131
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002132 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002133 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002134
Johan Hedberg92da6092013-03-15 17:06:55 -05002135 err = hci_req_run(&req, add_uuid_complete);
2136 if (err < 0) {
2137 if (err != -ENODATA)
2138 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002139
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002140 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2141 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002142 goto failed;
2143 }
2144
2145 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002146 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002147 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002148 goto failed;
2149 }
2150
2151 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002152
2153failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002154 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002155 return err;
2156}
2157
Johan Hedberg24b78d02012-02-23 23:24:30 +02002158static bool enable_service_cache(struct hci_dev *hdev)
2159{
2160 if (!hdev_is_powered(hdev))
2161 return false;
2162
Marcel Holtmann238be782015-03-13 02:11:06 -07002163 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002164 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2165 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002166 return true;
2167 }
2168
2169 return false;
2170}
2171
Marcel Holtmann1904a852015-01-11 13:50:44 -08002172static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002173{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002174 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002175
2176 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2177}
2178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002179static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002180 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002181{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002182 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002183 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002184 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002185 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 -05002186 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002187 int err, found;
2188
Marcel Holtmann181d6952020-05-06 09:57:47 +02002189 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002190
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002191 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002192
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002193 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002194 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2195 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002196 goto unlock;
2197 }
2198
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002200 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002201
Johan Hedberg24b78d02012-02-23 23:24:30 +02002202 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002203 err = mgmt_cmd_complete(sk, hdev->id,
2204 MGMT_OP_REMOVE_UUID,
2205 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002206 goto unlock;
2207 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002208
Johan Hedberg9246a862012-02-23 21:33:16 +02002209 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002210 }
2211
2212 found = 0;
2213
Johan Hedberg056341c2013-01-27 00:31:30 +02002214 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002215 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2216 continue;
2217
2218 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002219 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002220 found++;
2221 }
2222
2223 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002224 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2225 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002226 goto unlock;
2227 }
2228
Johan Hedberg9246a862012-02-23 21:33:16 +02002229update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002230 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002231
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002232 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002233 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002234
Johan Hedberg92da6092013-03-15 17:06:55 -05002235 err = hci_req_run(&req, remove_uuid_complete);
2236 if (err < 0) {
2237 if (err != -ENODATA)
2238 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002239
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002240 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2241 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002242 goto unlock;
2243 }
2244
2245 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002247 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002248 goto unlock;
2249 }
2250
2251 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002252
2253unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002254 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002255 return err;
2256}
2257
Marcel Holtmann1904a852015-01-11 13:50:44 -08002258static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002259{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002260 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002261
2262 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2263}
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002267{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002268 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002269 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002270 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002271 int err;
2272
Marcel Holtmann181d6952020-05-06 09:57:47 +02002273 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002274
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002275 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2277 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002278
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002279 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002280
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002281 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002282 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2283 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002284 goto unlock;
2285 }
2286
2287 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002288 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2289 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002290 goto unlock;
2291 }
2292
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002293 hdev->major_class = cp->major;
2294 hdev->minor_class = cp->minor;
2295
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002296 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002297 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2298 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002299 goto unlock;
2300 }
2301
Johan Hedberg890ea892013-03-15 17:06:52 -05002302 hci_req_init(&req, hdev);
2303
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002304 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002305 hci_dev_unlock(hdev);
2306 cancel_delayed_work_sync(&hdev->service_cache);
2307 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002308 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002309 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002310
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002311 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002312
Johan Hedberg92da6092013-03-15 17:06:55 -05002313 err = hci_req_run(&req, set_class_complete);
2314 if (err < 0) {
2315 if (err != -ENODATA)
2316 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002317
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002318 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2319 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002320 goto unlock;
2321 }
2322
2323 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002324 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002325 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002326 goto unlock;
2327 }
2328
2329 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002330
Johan Hedbergb5235a62012-02-21 14:32:24 +02002331unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002332 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002333 return err;
2334}
2335
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002336static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002337 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002339 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002340 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2341 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002342 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002343 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002344 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002345
Marcel Holtmann181d6952020-05-06 09:57:47 +02002346 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002347
2348 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002349 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2350 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002351
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002352 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002353 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002354 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2355 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002356 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2357 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002358 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002360 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002361 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002362 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2363 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002364 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2365 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002366 }
2367
Johan Hedberg4ae143012013-01-20 14:27:13 +02002368 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002369 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002371
Marcel Holtmann181d6952020-05-06 09:57:47 +02002372 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2373 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002374
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002375 for (i = 0; i < key_count; i++) {
2376 struct mgmt_link_key_info *key = &cp->keys[i];
2377
Marcel Holtmann8e991132014-01-10 02:07:25 -08002378 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002379 return mgmt_cmd_status(sk, hdev->id,
2380 MGMT_OP_LOAD_LINK_KEYS,
2381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002382 }
2383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002385
2386 hci_link_keys_clear(hdev);
2387
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002388 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002389 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002390 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002391 changed = hci_dev_test_and_clear_flag(hdev,
2392 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002393
2394 if (changed)
2395 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002396
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002397 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002398 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002399
Alain Michaud600a8742020-01-07 00:43:17 +00002400 if (hci_is_blocked_key(hdev,
2401 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2402 key->val)) {
2403 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2404 &key->addr.bdaddr);
2405 continue;
2406 }
2407
Johan Hedberg58e92932014-06-24 14:00:26 +03002408 /* Always ignore debug keys and require a new pairing if
2409 * the user wants to use them.
2410 */
2411 if (key->type == HCI_LK_DEBUG_COMBINATION)
2412 continue;
2413
Johan Hedberg7652ff62014-06-24 13:15:49 +03002414 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2415 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002416 }
2417
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002418 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002419
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002420 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002421
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002422 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002423}
2424
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002425static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002427{
2428 struct mgmt_ev_device_unpaired ev;
2429
2430 bacpy(&ev.addr.bdaddr, bdaddr);
2431 ev.addr.type = addr_type;
2432
2433 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002434 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002438 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002439{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002440 struct mgmt_cp_unpair_device *cp = data;
2441 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002442 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002443 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002445 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002446 int err;
2447
Johan Hedberga8a1d192011-11-10 15:54:38 +02002448 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002449 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2450 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002451
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002452 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002453 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2454 MGMT_STATUS_INVALID_PARAMS,
2455 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002456
Johan Hedberg118da702013-01-20 14:27:20 +02002457 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002458 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2459 MGMT_STATUS_INVALID_PARAMS,
2460 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002461
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002462 hci_dev_lock(hdev);
2463
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002464 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002465 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2466 MGMT_STATUS_NOT_POWERED, &rp,
2467 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002468 goto unlock;
2469 }
2470
Johan Hedberge0b2b272014-02-18 17:14:31 +02002471 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002472 /* If disconnection is requested, then look up the
2473 * connection. If the remote device is connected, it
2474 * will be later used to terminate the link.
2475 *
2476 * Setting it to NULL explicitly will cause no
2477 * termination of the link.
2478 */
2479 if (cp->disconnect)
2480 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2481 &cp->addr.bdaddr);
2482 else
2483 conn = NULL;
2484
Johan Hedberg124f6e32012-02-09 13:50:12 +02002485 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002486 if (err < 0) {
2487 err = mgmt_cmd_complete(sk, hdev->id,
2488 MGMT_OP_UNPAIR_DEVICE,
2489 MGMT_STATUS_NOT_PAIRED, &rp,
2490 sizeof(rp));
2491 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002492 }
2493
Johan Hedbergec182f02015-10-21 18:03:03 +03002494 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002495 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002496
Johan Hedbergec182f02015-10-21 18:03:03 +03002497 /* LE address type */
2498 addr_type = le_addr_type(cp->addr.type);
2499
Matias Karhumaacb28c302018-09-26 09:13:46 +03002500 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2501 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002502 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002503 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2504 MGMT_STATUS_NOT_PAIRED, &rp,
2505 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002506 goto unlock;
2507 }
2508
Johan Hedbergec182f02015-10-21 18:03:03 +03002509 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2510 if (!conn) {
2511 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2512 goto done;
2513 }
2514
Johan Hedbergc81d5552015-10-22 09:38:35 +03002515
Johan Hedbergec182f02015-10-21 18:03:03 +03002516 /* Defer clearing up the connection parameters until closing to
2517 * give a chance of keeping them if a repairing happens.
2518 */
2519 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2520
Johan Hedbergfc643612015-10-22 09:38:31 +03002521 /* Disable auto-connection parameters if present */
2522 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2523 if (params) {
2524 if (params->explicit_connect)
2525 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2526 else
2527 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2528 }
2529
Johan Hedbergec182f02015-10-21 18:03:03 +03002530 /* If disconnection is not requested, then clear the connection
2531 * variable so that the link is not terminated.
2532 */
2533 if (!cp->disconnect)
2534 conn = NULL;
2535
2536done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002537 /* If the connection variable is set, then termination of the
2538 * link is requested.
2539 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002540 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002541 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2542 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002543 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002544 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002545 }
2546
Johan Hedberg124f6e32012-02-09 13:50:12 +02002547 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002549 if (!cmd) {
2550 err = -ENOMEM;
2551 goto unlock;
2552 }
2553
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002554 cmd->cmd_complete = addr_cmd_complete;
2555
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002556 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002557 if (err < 0)
2558 mgmt_pending_remove(cmd);
2559
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002560unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002561 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002562 return err;
2563}
2564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002567{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002569 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002570 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002571 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002572 int err;
2573
Marcel Holtmann181d6952020-05-06 09:57:47 +02002574 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002575
Johan Hedberg06a63b12013-01-20 14:27:21 +02002576 memset(&rp, 0, sizeof(rp));
2577 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2578 rp.addr.type = cp->addr.type;
2579
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002580 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002581 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2582 MGMT_STATUS_INVALID_PARAMS,
2583 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002585 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002586
2587 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002588 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2589 MGMT_STATUS_NOT_POWERED, &rp,
2590 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591 goto failed;
2592 }
2593
Johan Hedberg333ae952015-03-17 13:48:47 +02002594 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002595 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2596 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002597 goto failed;
2598 }
2599
Andre Guedes591f47f2012-04-24 21:02:49 -03002600 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002601 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2602 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002603 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002604 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2605 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002606
Vishal Agarwalf9607272012-06-13 05:32:43 +05302607 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002608 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2609 MGMT_STATUS_NOT_CONNECTED, &rp,
2610 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002611 goto failed;
2612 }
2613
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002614 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002615 if (!cmd) {
2616 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002617 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002618 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002619
Johan Hedbergf5818c22014-12-05 13:36:02 +02002620 cmd->cmd_complete = generic_cmd_complete;
2621
Johan Hedberge3f2f922014-08-18 20:33:33 +03002622 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002623 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002624 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002625
2626failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002628 return err;
2629}
2630
Andre Guedes57c14772012-04-24 21:02:50 -03002631static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002632{
2633 switch (link_type) {
2634 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002635 switch (addr_type) {
2636 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002637 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002638
Johan Hedberg48264f02011-11-09 13:58:58 +02002639 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002640 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002641 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002642 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002643
Johan Hedberg4c659c32011-11-07 23:13:39 +02002644 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002645 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002646 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002647 }
2648}
2649
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002650static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2651 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002652{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002653 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002654 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002655 int err;
2656 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002657
Marcel Holtmann181d6952020-05-06 09:57:47 +02002658 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002660 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002661
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002662 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002663 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2664 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002665 goto unlock;
2666 }
2667
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002668 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002669 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2670 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002671 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002672 }
2673
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002674 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002675 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002676 err = -ENOMEM;
2677 goto unlock;
2678 }
2679
Johan Hedberg2784eb42011-01-21 13:56:35 +02002680 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002681 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002682 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2683 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002684 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002685 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002686 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002687 continue;
2688 i++;
2689 }
2690
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002691 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002692
Johan Hedberg4c659c32011-11-07 23:13:39 +02002693 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002694 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002695 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002696
Johan Hedberga38528f2011-01-22 06:46:43 +02002697 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002698
2699unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002700 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002701 return err;
2702}
2703
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002704static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002706{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002707 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002708 int err;
2709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002710 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002712 if (!cmd)
2713 return -ENOMEM;
2714
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002715 cmd->cmd_complete = addr_cmd_complete;
2716
Johan Hedbergd8457692012-02-17 14:24:57 +02002717 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002719 if (err < 0)
2720 mgmt_pending_remove(cmd);
2721
2722 return err;
2723}
2724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002725static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002726 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002727{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002728 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002731 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002732 int err;
2733
Marcel Holtmann181d6952020-05-06 09:57:47 +02002734 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002735
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002736 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002737
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002738 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002739 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2740 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002741 goto failed;
2742 }
2743
Johan Hedbergd8457692012-02-17 14:24:57 +02002744 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002745 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002746 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2747 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002748 goto failed;
2749 }
2750
2751 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002752 struct mgmt_cp_pin_code_neg_reply ncp;
2753
2754 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002755
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002756 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002757
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002758 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002759 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002760 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2761 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002762
2763 goto failed;
2764 }
2765
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002766 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002767 if (!cmd) {
2768 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002769 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002770 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002771
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002772 cmd->cmd_complete = addr_cmd_complete;
2773
Johan Hedbergd8457692012-02-17 14:24:57 +02002774 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002775 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002776 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002777
2778 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2779 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002780 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002781
2782failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002783 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002784 return err;
2785}
2786
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002787static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2788 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002789{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002791
Marcel Holtmann181d6952020-05-06 09:57:47 +02002792 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002793
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002794 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002795 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2796 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002797
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002798 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002799
2800 hdev->io_capability = cp->io_capability;
2801
Marcel Holtmann181d6952020-05-06 09:57:47 +02002802 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002804 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002805
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002806 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2807 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002808}
2809
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002810static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002811{
2812 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002813 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002814
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002815 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002816 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2817 continue;
2818
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819 if (cmd->user_data != conn)
2820 continue;
2821
2822 return cmd;
2823 }
2824
2825 return NULL;
2826}
2827
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002828static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002829{
2830 struct mgmt_rp_pair_device rp;
2831 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002832 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002833
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002834 bacpy(&rp.addr.bdaddr, &conn->dst);
2835 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002836
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002837 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2838 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002839
2840 /* So we don't get further callbacks for this connection */
2841 conn->connect_cfm_cb = NULL;
2842 conn->security_cfm_cb = NULL;
2843 conn->disconn_cfm_cb = NULL;
2844
David Herrmann76a68ba2013-04-06 20:28:37 +02002845 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002846
2847 /* The device is paired so there is no need to remove
2848 * its connection parameters anymore.
2849 */
2850 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002851
2852 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002853
2854 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855}
2856
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002857void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2858{
2859 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002860 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002861
2862 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002863 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002864 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002865 mgmt_pending_remove(cmd);
2866 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002867}
2868
Johan Hedberge9a416b2011-02-19 12:05:56 -03002869static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2870{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002871 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872
2873 BT_DBG("status %u", status);
2874
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002875 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002876 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002877 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002878 return;
2879 }
2880
2881 cmd->cmd_complete(cmd, mgmt_status(status));
2882 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002883}
2884
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002885static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302886{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002887 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302888
2889 BT_DBG("status %u", status);
2890
2891 if (!status)
2892 return;
2893
2894 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002895 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302896 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002897 return;
2898 }
2899
2900 cmd->cmd_complete(cmd, mgmt_status(status));
2901 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302902}
2903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002904static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002905 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002906{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002907 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002908 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002909 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002910 u8 sec_level, auth_type;
2911 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002912 int err;
2913
Marcel Holtmann181d6952020-05-06 09:57:47 +02002914 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002915
Szymon Jancf950a30e2013-01-18 12:48:07 +01002916 memset(&rp, 0, sizeof(rp));
2917 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2918 rp.addr.type = cp->addr.type;
2919
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002920 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002921 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2922 MGMT_STATUS_INVALID_PARAMS,
2923 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002924
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002925 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002926 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2927 MGMT_STATUS_INVALID_PARAMS,
2928 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002929
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002930 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002931
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002932 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002933 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2934 MGMT_STATUS_NOT_POWERED, &rp,
2935 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002936 goto unlock;
2937 }
2938
Johan Hedberg55e76b32015-03-10 22:34:40 +02002939 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2940 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2941 MGMT_STATUS_ALREADY_PAIRED, &rp,
2942 sizeof(rp));
2943 goto unlock;
2944 }
2945
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002946 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002947 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002948
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002949 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002950 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002951 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002952 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002953 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002954 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002955
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002956 /* When pairing a new device, it is expected to remember
2957 * this device for future connections. Adding the connection
2958 * parameter information ahead of time allows tracking
2959 * of the slave preferred values and will speed up any
2960 * further connection establishment.
2961 *
2962 * If connection parameters already exist, then they
2963 * will be kept and this function does nothing.
2964 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002965 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2966
2967 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2968 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002969
Manish Mandlik76b13992020-06-17 16:39:19 +02002970 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2971 sec_level, HCI_LE_CONN_TIMEOUT,
2972 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002973 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002974
Ville Tervo30e76272011-02-22 16:10:53 -03002975 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002976 int status;
2977
2978 if (PTR_ERR(conn) == -EBUSY)
2979 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002980 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2981 status = MGMT_STATUS_NOT_SUPPORTED;
2982 else if (PTR_ERR(conn) == -ECONNREFUSED)
2983 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002984 else
2985 status = MGMT_STATUS_CONNECT_FAILED;
2986
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002987 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2988 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002989 goto unlock;
2990 }
2991
2992 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002993 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002994 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2995 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002996 goto unlock;
2997 }
2998
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002999 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003000 if (!cmd) {
3001 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003002 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003003 goto unlock;
3004 }
3005
Johan Hedberg04ab2742014-12-05 13:36:04 +02003006 cmd->cmd_complete = pairing_complete;
3007
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003008 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003009 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003010 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003011 conn->security_cfm_cb = pairing_complete_cb;
3012 conn->disconn_cfm_cb = pairing_complete_cb;
3013 } else {
3014 conn->connect_cfm_cb = le_pairing_complete_cb;
3015 conn->security_cfm_cb = le_pairing_complete_cb;
3016 conn->disconn_cfm_cb = le_pairing_complete_cb;
3017 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003018
Johan Hedberge9a416b2011-02-19 12:05:56 -03003019 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003020 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003021
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003022 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003023 hci_conn_security(conn, sec_level, auth_type, true)) {
3024 cmd->cmd_complete(cmd, 0);
3025 mgmt_pending_remove(cmd);
3026 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003027
3028 err = 0;
3029
3030unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003031 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003032 return err;
3033}
3034
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3036 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003037{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003038 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003039 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003040 struct hci_conn *conn;
3041 int err;
3042
Marcel Holtmann181d6952020-05-06 09:57:47 +02003043 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003044
Johan Hedberg28424702012-02-02 04:02:29 +02003045 hci_dev_lock(hdev);
3046
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003047 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003048 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3049 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003050 goto unlock;
3051 }
3052
Johan Hedberg333ae952015-03-17 13:48:47 +02003053 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003054 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003055 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3056 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003057 goto unlock;
3058 }
3059
3060 conn = cmd->user_data;
3061
3062 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003063 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3064 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003065 goto unlock;
3066 }
3067
Johan Hedberga511b352014-12-11 21:45:45 +02003068 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3069 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003070
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003071 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3072 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003073
3074 /* Since user doesn't want to proceed with the connection, abort any
3075 * ongoing pairing and then terminate the link if it was created
3076 * because of the pair device action.
3077 */
3078 if (addr->type == BDADDR_BREDR)
3079 hci_remove_link_key(hdev, &addr->bdaddr);
3080 else
3081 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3082 le_addr_type(addr->type));
3083
3084 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3085 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3086
Johan Hedberg28424702012-02-02 04:02:29 +02003087unlock:
3088 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003089 return err;
3090}
3091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003092static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003093 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003094 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003095{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003096 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003097 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003098 int err;
3099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003101
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003102 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003103 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3104 MGMT_STATUS_NOT_POWERED, addr,
3105 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003106 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003107 }
3108
Johan Hedberg1707c602013-03-15 17:07:15 -05003109 if (addr->type == BDADDR_BREDR)
3110 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003111 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003112 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3113 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003114
Johan Hedberg272d90d2012-02-09 15:26:12 +02003115 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003116 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3117 MGMT_STATUS_NOT_CONNECTED, addr,
3118 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003119 goto done;
3120 }
3121
Johan Hedberg1707c602013-03-15 17:07:15 -05003122 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003123 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003124 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003125 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3126 MGMT_STATUS_SUCCESS, addr,
3127 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003128 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003129 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3130 MGMT_STATUS_FAILED, addr,
3131 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003132
Brian Gix47c15e22011-11-16 13:53:14 -08003133 goto done;
3134 }
3135
Johan Hedberg1707c602013-03-15 17:07:15 -05003136 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003137 if (!cmd) {
3138 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003139 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003140 }
3141
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003142 cmd->cmd_complete = addr_cmd_complete;
3143
Brian Gix0df4c182011-11-16 13:53:13 -08003144 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003145 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3146 struct hci_cp_user_passkey_reply cp;
3147
Johan Hedberg1707c602013-03-15 17:07:15 -05003148 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003149 cp.passkey = passkey;
3150 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3151 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003152 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3153 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003154
Johan Hedberga664b5b2011-02-19 12:06:02 -03003155 if (err < 0)
3156 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003157
Brian Gix0df4c182011-11-16 13:53:13 -08003158done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003159 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003160 return err;
3161}
3162
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303163static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3164 void *data, u16 len)
3165{
3166 struct mgmt_cp_pin_code_neg_reply *cp = data;
3167
Marcel Holtmann181d6952020-05-06 09:57:47 +02003168 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303169
Johan Hedberg1707c602013-03-15 17:07:15 -05003170 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303171 MGMT_OP_PIN_CODE_NEG_REPLY,
3172 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3173}
3174
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3176 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003177{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003178 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003179
Marcel Holtmann181d6952020-05-06 09:57:47 +02003180 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003181
3182 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003183 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3184 MGMT_STATUS_INVALID_PARAMS);
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_REPLY,
3188 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003189}
3190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003191static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003193{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003194 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003195
Marcel Holtmann181d6952020-05-06 09:57:47 +02003196 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -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_CONFIRM_NEG_REPLY,
3200 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003201}
3202
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003203static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3204 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003206 struct mgmt_cp_user_passkey_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_REPLY,
3212 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003213}
3214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003215static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003217{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003218 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003219
Marcel Holtmann181d6952020-05-06 09:57:47 +02003220 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003221
Johan Hedberg1707c602013-03-15 17:07:15 -05003222 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3224 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003225}
3226
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003227static void adv_expire(struct hci_dev *hdev, u32 flags)
3228{
3229 struct adv_info *adv_instance;
3230 struct hci_request req;
3231 int err;
3232
3233 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3234 if (!adv_instance)
3235 return;
3236
3237 /* stop if current instance doesn't need to be changed */
3238 if (!(adv_instance->flags & flags))
3239 return;
3240
3241 cancel_adv_timeout(hdev);
3242
3243 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3244 if (!adv_instance)
3245 return;
3246
3247 hci_req_init(&req, hdev);
3248 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3249 true);
3250 if (err)
3251 return;
3252
3253 hci_req_run(&req, NULL);
3254}
3255
Marcel Holtmann1904a852015-01-11 13:50:44 -08003256static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003257{
3258 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003259 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003260
Marcel Holtmann181d6952020-05-06 09:57:47 +02003261 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003262
3263 hci_dev_lock(hdev);
3264
Johan Hedberg333ae952015-03-17 13:48:47 +02003265 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003266 if (!cmd)
3267 goto unlock;
3268
3269 cp = cmd->param;
3270
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003271 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003272 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3273 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003274 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003275 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3276 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003277
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003278 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3279 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3280 }
3281
Johan Hedberg13928972013-03-15 17:07:00 -05003282 mgmt_pending_remove(cmd);
3283
3284unlock:
3285 hci_dev_unlock(hdev);
3286}
3287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003288static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003289 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003290{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003291 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003292 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003293 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003294 int err;
3295
Marcel Holtmann181d6952020-05-06 09:57:47 +02003296 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003297
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003298 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003299
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003300 /* If the old values are the same as the new ones just return a
3301 * direct command complete event.
3302 */
3303 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3304 !memcmp(hdev->short_name, cp->short_name,
3305 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003306 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3307 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003308 goto failed;
3309 }
3310
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003311 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003312
Johan Hedbergb5235a62012-02-21 14:32:24 +02003313 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003314 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003315
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003316 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3317 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003318 if (err < 0)
3319 goto failed;
3320
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003321 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3322 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003323 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003324
Johan Hedbergb5235a62012-02-21 14:32:24 +02003325 goto failed;
3326 }
3327
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003328 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003329 if (!cmd) {
3330 err = -ENOMEM;
3331 goto failed;
3332 }
3333
Johan Hedberg13928972013-03-15 17:07:00 -05003334 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3335
Johan Hedberg890ea892013-03-15 17:06:52 -05003336 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003337
3338 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003339 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003340 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003341 }
3342
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003343 /* The name is stored in the scan response data and so
Zheng Yongjun91641b72021-06-02 14:54:58 +08003344 * no need to update the advertising data here.
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003345 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003346 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003347 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003348
Johan Hedberg13928972013-03-15 17:07:00 -05003349 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003350 if (err < 0)
3351 mgmt_pending_remove(cmd);
3352
3353failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003354 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003355 return err;
3356}
3357
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003358static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3359 u16 len)
3360{
3361 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003362 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003363 int err;
3364
Marcel Holtmann181d6952020-05-06 09:57:47 +02003365 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003366
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003367 if (!lmp_le_capable(hdev))
3368 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3369 MGMT_STATUS_NOT_SUPPORTED);
3370
Alain Michaud6613bab2020-01-22 19:47:44 +00003371 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003372
3373 hci_dev_lock(hdev);
3374
Alain Michaud6613bab2020-01-22 19:47:44 +00003375 if (hdev->appearance != appearance) {
3376 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003377
3378 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3379 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003380
3381 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003382 }
3383
3384 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3385 0);
3386
3387 hci_dev_unlock(hdev);
3388
3389 return err;
3390}
3391
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303392static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3393 void *data, u16 len)
3394{
Reo Shiseki353021582020-11-19 16:37:11 +09003395 struct mgmt_rp_get_phy_configuration rp;
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303396
Marcel Holtmann181d6952020-05-06 09:57:47 +02003397 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303398
3399 hci_dev_lock(hdev);
3400
3401 memset(&rp, 0, sizeof(rp));
3402
3403 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3404 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3405 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3406
3407 hci_dev_unlock(hdev);
3408
3409 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3410 &rp, sizeof(rp));
3411}
3412
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303413int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3414{
3415 struct mgmt_ev_phy_configuration_changed ev;
3416
3417 memset(&ev, 0, sizeof(ev));
3418
3419 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3420
3421 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3422 sizeof(ev), skip);
3423}
3424
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303425static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3426 u16 opcode, struct sk_buff *skb)
3427{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303428 struct mgmt_pending_cmd *cmd;
3429
Marcel Holtmann181d6952020-05-06 09:57:47 +02003430 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303431
3432 hci_dev_lock(hdev);
3433
3434 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3435 if (!cmd)
3436 goto unlock;
3437
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303438 if (status) {
3439 mgmt_cmd_status(cmd->sk, hdev->id,
3440 MGMT_OP_SET_PHY_CONFIGURATION,
3441 mgmt_status(status));
3442 } else {
3443 mgmt_cmd_complete(cmd->sk, hdev->id,
3444 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3445 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303446
3447 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303448 }
3449
3450 mgmt_pending_remove(cmd);
3451
3452unlock:
3453 hci_dev_unlock(hdev);
3454}
3455
3456static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3457 void *data, u16 len)
3458{
Reo Shiseki353021582020-11-19 16:37:11 +09003459 struct mgmt_cp_set_phy_configuration *cp = data;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303460 struct hci_cp_le_set_default_phy cp_phy;
3461 struct mgmt_pending_cmd *cmd;
3462 struct hci_request req;
3463 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3464 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303465 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303466 int err;
3467
Marcel Holtmann181d6952020-05-06 09:57:47 +02003468 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303469
3470 configurable_phys = get_configurable_phys(hdev);
3471 supported_phys = get_supported_phys(hdev);
3472 selected_phys = __le32_to_cpu(cp->selected_phys);
3473
3474 if (selected_phys & ~supported_phys)
3475 return mgmt_cmd_status(sk, hdev->id,
3476 MGMT_OP_SET_PHY_CONFIGURATION,
3477 MGMT_STATUS_INVALID_PARAMS);
3478
3479 unconfigure_phys = supported_phys & ~configurable_phys;
3480
3481 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3482 return mgmt_cmd_status(sk, hdev->id,
3483 MGMT_OP_SET_PHY_CONFIGURATION,
3484 MGMT_STATUS_INVALID_PARAMS);
3485
3486 if (selected_phys == get_selected_phys(hdev))
3487 return mgmt_cmd_complete(sk, hdev->id,
3488 MGMT_OP_SET_PHY_CONFIGURATION,
3489 0, NULL, 0);
3490
3491 hci_dev_lock(hdev);
3492
3493 if (!hdev_is_powered(hdev)) {
3494 err = mgmt_cmd_status(sk, hdev->id,
3495 MGMT_OP_SET_PHY_CONFIGURATION,
3496 MGMT_STATUS_REJECTED);
3497 goto unlock;
3498 }
3499
3500 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3501 err = mgmt_cmd_status(sk, hdev->id,
3502 MGMT_OP_SET_PHY_CONFIGURATION,
3503 MGMT_STATUS_BUSY);
3504 goto unlock;
3505 }
3506
3507 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3508 pkt_type |= (HCI_DH3 | HCI_DM3);
3509 else
3510 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3511
3512 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3513 pkt_type |= (HCI_DH5 | HCI_DM5);
3514 else
3515 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3516
3517 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3518 pkt_type &= ~HCI_2DH1;
3519 else
3520 pkt_type |= HCI_2DH1;
3521
3522 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3523 pkt_type &= ~HCI_2DH3;
3524 else
3525 pkt_type |= HCI_2DH3;
3526
3527 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3528 pkt_type &= ~HCI_2DH5;
3529 else
3530 pkt_type |= HCI_2DH5;
3531
3532 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3533 pkt_type &= ~HCI_3DH1;
3534 else
3535 pkt_type |= HCI_3DH1;
3536
3537 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3538 pkt_type &= ~HCI_3DH3;
3539 else
3540 pkt_type |= HCI_3DH3;
3541
3542 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3543 pkt_type &= ~HCI_3DH5;
3544 else
3545 pkt_type |= HCI_3DH5;
3546
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303547 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303548 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303549 changed = true;
3550 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303551
3552 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3553 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303554 if (changed)
3555 mgmt_phy_configuration_changed(hdev, sk);
3556
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303557 err = mgmt_cmd_complete(sk, hdev->id,
3558 MGMT_OP_SET_PHY_CONFIGURATION,
3559 0, NULL, 0);
3560
3561 goto unlock;
3562 }
3563
3564 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3565 len);
3566 if (!cmd) {
3567 err = -ENOMEM;
3568 goto unlock;
3569 }
3570
3571 hci_req_init(&req, hdev);
3572
3573 memset(&cp_phy, 0, sizeof(cp_phy));
3574
3575 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3576 cp_phy.all_phys |= 0x01;
3577
3578 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3579 cp_phy.all_phys |= 0x02;
3580
3581 if (selected_phys & MGMT_PHY_LE_1M_TX)
3582 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3583
3584 if (selected_phys & MGMT_PHY_LE_2M_TX)
3585 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3586
3587 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3588 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3589
3590 if (selected_phys & MGMT_PHY_LE_1M_RX)
3591 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3592
3593 if (selected_phys & MGMT_PHY_LE_2M_RX)
3594 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3595
3596 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3597 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3598
3599 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3600
3601 err = hci_req_run_skb(&req, set_default_phy_complete);
3602 if (err < 0)
3603 mgmt_pending_remove(cmd);
3604
3605unlock:
3606 hci_dev_unlock(hdev);
3607
3608 return err;
3609}
3610
Alain Michaud600a8742020-01-07 00:43:17 +00003611static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3612 u16 len)
3613{
3614 int err = MGMT_STATUS_SUCCESS;
3615 struct mgmt_cp_set_blocked_keys *keys = data;
3616 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3617 sizeof(struct mgmt_blocked_key_info));
3618 u16 key_count, expected_len;
3619 int i;
3620
Marcel Holtmann181d6952020-05-06 09:57:47 +02003621 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003622
3623 key_count = __le16_to_cpu(keys->key_count);
3624 if (key_count > max_key_count) {
3625 bt_dev_err(hdev, "too big key_count value %u", key_count);
3626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3627 MGMT_STATUS_INVALID_PARAMS);
3628 }
3629
3630 expected_len = struct_size(keys, keys, key_count);
3631 if (expected_len != len) {
3632 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3633 expected_len, len);
3634 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3635 MGMT_STATUS_INVALID_PARAMS);
3636 }
3637
3638 hci_dev_lock(hdev);
3639
3640 hci_blocked_keys_clear(hdev);
3641
3642 for (i = 0; i < keys->key_count; ++i) {
3643 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3644
3645 if (!b) {
3646 err = MGMT_STATUS_NO_RESOURCES;
3647 break;
3648 }
3649
3650 b->type = keys->keys[i].type;
3651 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3652 list_add_rcu(&b->list, &hdev->blocked_keys);
3653 }
3654 hci_dev_unlock(hdev);
3655
3656 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3657 err, NULL, 0);
3658}
3659
Alain Michaud00bce3f2020-03-05 16:14:59 +00003660static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3661 void *data, u16 len)
3662{
3663 struct mgmt_mode *cp = data;
3664 int err;
3665 bool changed = false;
3666
Marcel Holtmann181d6952020-05-06 09:57:47 +02003667 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003668
3669 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3670 return mgmt_cmd_status(sk, hdev->id,
3671 MGMT_OP_SET_WIDEBAND_SPEECH,
3672 MGMT_STATUS_NOT_SUPPORTED);
3673
3674 if (cp->val != 0x00 && cp->val != 0x01)
3675 return mgmt_cmd_status(sk, hdev->id,
3676 MGMT_OP_SET_WIDEBAND_SPEECH,
3677 MGMT_STATUS_INVALID_PARAMS);
3678
3679 hci_dev_lock(hdev);
3680
3681 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3682 err = mgmt_cmd_status(sk, hdev->id,
3683 MGMT_OP_SET_WIDEBAND_SPEECH,
3684 MGMT_STATUS_BUSY);
3685 goto unlock;
3686 }
3687
3688 if (hdev_is_powered(hdev) &&
3689 !!cp->val != hci_dev_test_flag(hdev,
3690 HCI_WIDEBAND_SPEECH_ENABLED)) {
3691 err = mgmt_cmd_status(sk, hdev->id,
3692 MGMT_OP_SET_WIDEBAND_SPEECH,
3693 MGMT_STATUS_REJECTED);
3694 goto unlock;
3695 }
3696
3697 if (cp->val)
3698 changed = !hci_dev_test_and_set_flag(hdev,
3699 HCI_WIDEBAND_SPEECH_ENABLED);
3700 else
3701 changed = hci_dev_test_and_clear_flag(hdev,
3702 HCI_WIDEBAND_SPEECH_ENABLED);
3703
3704 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3705 if (err < 0)
3706 goto unlock;
3707
3708 if (changed)
3709 err = new_settings(hdev, sk);
3710
3711unlock:
3712 hci_dev_unlock(hdev);
3713 return err;
3714}
3715
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003716static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
3717 void *data, u16 data_len)
Marcel Holtmannbc292252020-04-03 21:44:05 +02003718{
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003719 char buf[20];
3720 struct mgmt_rp_read_controller_cap *rp = (void *)buf;
3721 u16 cap_len = 0;
Marcel Holtmannbc292252020-04-03 21:44:05 +02003722 u8 flags = 0;
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003723 u8 tx_power_range[2];
Marcel Holtmannbc292252020-04-03 21:44:05 +02003724
3725 bt_dev_dbg(hdev, "sock %p", sk);
3726
3727 memset(&buf, 0, sizeof(buf));
3728
3729 hci_dev_lock(hdev);
3730
3731 /* When the Read Simple Pairing Options command is supported, then
3732 * the remote public key validation is supported.
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003733 *
3734 * Alternatively, when Microsoft extensions are available, they can
3735 * indicate support for public key validation as well.
Marcel Holtmannbc292252020-04-03 21:44:05 +02003736 */
Marcel Holtmanna61d6712021-04-06 21:55:56 +02003737 if ((hdev->commands[41] & 0x08) || msft_curve_validity(hdev))
Marcel Holtmannbc292252020-04-03 21:44:05 +02003738 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3739
3740 flags |= 0x02; /* Remote public key validation (LE) */
3741
3742 /* When the Read Encryption Key Size command is supported, then the
3743 * encryption key size is enforced.
3744 */
3745 if (hdev->commands[20] & 0x10)
3746 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3747
3748 flags |= 0x08; /* Encryption key size enforcement (LE) */
3749
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003750 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_SEC_FLAGS,
3751 &flags, 1);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003752
3753 /* When the Read Simple Pairing Options command is supported, then
3754 * also max encryption key size information is provided.
3755 */
3756 if (hdev->commands[41] & 0x08)
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003757 cap_len = eir_append_le16(rp->cap, cap_len,
3758 MGMT_CAP_MAX_ENC_KEY_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02003759 hdev->max_enc_key_size);
3760
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003761 cap_len = eir_append_le16(rp->cap, cap_len,
3762 MGMT_CAP_SMP_MAX_ENC_KEY_SIZE,
3763 SMP_MAX_ENC_KEY_SIZE);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003764
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003765 /* Append the min/max LE tx power parameters if we were able to fetch
3766 * it from the controller
3767 */
3768 if (hdev->commands[38] & 0x80) {
3769 memcpy(&tx_power_range[0], &hdev->min_le_tx_power, 1);
3770 memcpy(&tx_power_range[1], &hdev->max_le_tx_power, 1);
3771 cap_len = eir_append_data(rp->cap, cap_len, MGMT_CAP_LE_TX_PWR,
3772 tx_power_range, 2);
3773 }
3774
3775 rp->cap_len = cpu_to_le16(cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003776
3777 hci_dev_unlock(hdev);
3778
Daniel Winkler4d9b9522020-12-03 12:12:52 -08003779 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONTROLLER_CAP, 0,
3780 rp, sizeof(*rp) + cap_len);
Marcel Holtmannbc292252020-04-03 21:44:05 +02003781}
3782
Marcel Holtmanne625e502020-05-06 09:57:52 +02003783#ifdef CONFIG_BT_FEATURE_DEBUG
3784/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3785static const u8 debug_uuid[16] = {
3786 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3787 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3788};
3789#endif
3790
Alain Michaud15d8ce02020-07-07 17:46:06 +02003791/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3792static const u8 simult_central_periph_uuid[16] = {
3793 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3794 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3795};
3796
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303797/* 15c0a148-c273-11ea-b3de-0242ac130004 */
3798static const u8 rpa_resolution_uuid[16] = {
3799 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3,
3800 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
3801};
3802
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003803static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3804 void *data, u16 data_len)
3805{
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303806 char buf[62]; /* Enough space for 3 features */
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003807 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3808 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003809 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003810
3811 bt_dev_dbg(hdev, "sock %p", sk);
3812
3813 memset(&buf, 0, sizeof(buf));
3814
Marcel Holtmanne625e502020-05-06 09:57:52 +02003815#ifdef CONFIG_BT_FEATURE_DEBUG
3816 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003817 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003818
3819 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3820 rp->features[idx].flags = cpu_to_le32(flags);
3821 idx++;
3822 }
3823#endif
3824
Alain Michaud15d8ce02020-07-07 17:46:06 +02003825 if (hdev) {
3826 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3827 (hdev->le_states[4] & 0x08) && /* Central */
3828 (hdev->le_states[4] & 0x40) && /* Peripheral */
3829 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3830 flags = BIT(0);
3831 else
3832 flags = 0;
3833
3834 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3835 rp->features[idx].flags = cpu_to_le32(flags);
3836 idx++;
3837 }
3838
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303839 if (hdev && use_ll_privacy(hdev)) {
3840 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
3841 flags = BIT(0) | BIT(1);
3842 else
3843 flags = BIT(1);
3844
3845 memcpy(rp->features[idx].uuid, rpa_resolution_uuid, 16);
3846 rp->features[idx].flags = cpu_to_le32(flags);
3847 idx++;
3848 }
3849
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003850 rp->feature_count = cpu_to_le16(idx);
3851
3852 /* After reading the experimental features information, enable
3853 * the events to update client on any future change.
3854 */
3855 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3856
3857 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3858 MGMT_OP_READ_EXP_FEATURES_INFO,
3859 0, rp, sizeof(*rp) + (20 * idx));
3860}
3861
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303862static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
3863 struct sock *skip)
3864{
3865 struct mgmt_ev_exp_feature_changed ev;
3866
3867 memset(&ev, 0, sizeof(ev));
3868 memcpy(ev.uuid, rpa_resolution_uuid, 16);
3869 ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
3870
3871 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
3872 &ev, sizeof(ev),
3873 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3874
3875}
3876
Marcel Holtmanne625e502020-05-06 09:57:52 +02003877#ifdef CONFIG_BT_FEATURE_DEBUG
3878static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3879{
3880 struct mgmt_ev_exp_feature_changed ev;
3881
3882 memset(&ev, 0, sizeof(ev));
3883 memcpy(ev.uuid, debug_uuid, 16);
3884 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3885
3886 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3887 &ev, sizeof(ev),
3888 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3889}
3890#endif
3891
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003892static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3893 void *data, u16 data_len)
3894{
3895 struct mgmt_cp_set_exp_feature *cp = data;
3896 struct mgmt_rp_set_exp_feature rp;
3897
3898 bt_dev_dbg(hdev, "sock %p", sk);
3899
3900 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3901 memset(rp.uuid, 0, 16);
3902 rp.flags = cpu_to_le32(0);
3903
Marcel Holtmanne625e502020-05-06 09:57:52 +02003904#ifdef CONFIG_BT_FEATURE_DEBUG
3905 if (!hdev) {
3906 bool changed = bt_dbg_get();
3907
3908 bt_dbg_set(false);
3909
3910 if (changed)
3911 exp_debug_feature_changed(false, sk);
3912 }
3913#endif
3914
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303915 if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
3916 bool changed = hci_dev_test_flag(hdev,
3917 HCI_ENABLE_LL_PRIVACY);
3918
3919 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
3920
3921 if (changed)
3922 exp_ll_privacy_feature_changed(false, hdev, sk);
3923 }
3924
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003925 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3926
3927 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3928 MGMT_OP_SET_EXP_FEATURE, 0,
3929 &rp, sizeof(rp));
3930 }
3931
Marcel Holtmanne625e502020-05-06 09:57:52 +02003932#ifdef CONFIG_BT_FEATURE_DEBUG
3933 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3934 bool val, changed;
3935 int err;
3936
3937 /* Command requires to use the non-controller index */
3938 if (hdev)
3939 return mgmt_cmd_status(sk, hdev->id,
3940 MGMT_OP_SET_EXP_FEATURE,
3941 MGMT_STATUS_INVALID_INDEX);
3942
3943 /* Parameters are limited to a single octet */
3944 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3945 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3946 MGMT_OP_SET_EXP_FEATURE,
3947 MGMT_STATUS_INVALID_PARAMS);
3948
3949 /* Only boolean on/off is supported */
3950 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3951 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3952 MGMT_OP_SET_EXP_FEATURE,
3953 MGMT_STATUS_INVALID_PARAMS);
3954
3955 val = !!cp->param[0];
3956 changed = val ? !bt_dbg_get() : bt_dbg_get();
3957 bt_dbg_set(val);
3958
3959 memcpy(rp.uuid, debug_uuid, 16);
3960 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3961
3962 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3963
3964 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3965 MGMT_OP_SET_EXP_FEATURE, 0,
3966 &rp, sizeof(rp));
3967
3968 if (changed)
3969 exp_debug_feature_changed(val, sk);
3970
3971 return err;
3972 }
3973#endif
3974
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303975 if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) {
3976 bool val, changed;
3977 int err;
3978 u32 flags;
3979
3980 /* Command requires to use the controller index */
3981 if (!hdev)
3982 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3983 MGMT_OP_SET_EXP_FEATURE,
3984 MGMT_STATUS_INVALID_INDEX);
3985
3986 /* Changes can only be made when controller is powered down */
3987 if (hdev_is_powered(hdev))
3988 return mgmt_cmd_status(sk, hdev->id,
3989 MGMT_OP_SET_EXP_FEATURE,
Marcel Holtmann353cac02021-03-14 14:49:38 +01003990 MGMT_STATUS_REJECTED);
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05303991
3992 /* Parameters are limited to a single octet */
3993 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3994 return mgmt_cmd_status(sk, hdev->id,
3995 MGMT_OP_SET_EXP_FEATURE,
3996 MGMT_STATUS_INVALID_PARAMS);
3997
3998 /* Only boolean on/off is supported */
3999 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
4000 return mgmt_cmd_status(sk, hdev->id,
4001 MGMT_OP_SET_EXP_FEATURE,
4002 MGMT_STATUS_INVALID_PARAMS);
4003
4004 val = !!cp->param[0];
4005
4006 if (val) {
4007 changed = !hci_dev_test_flag(hdev,
4008 HCI_ENABLE_LL_PRIVACY);
4009 hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4010 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
4011
4012 /* Enable LL privacy + supported settings changed */
4013 flags = BIT(0) | BIT(1);
4014 } else {
4015 changed = hci_dev_test_flag(hdev,
4016 HCI_ENABLE_LL_PRIVACY);
4017 hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
4018
4019 /* Disable LL privacy + supported settings changed */
4020 flags = BIT(1);
4021 }
4022
4023 memcpy(rp.uuid, rpa_resolution_uuid, 16);
4024 rp.flags = cpu_to_le32(flags);
4025
4026 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
4027
4028 err = mgmt_cmd_complete(sk, hdev->id,
4029 MGMT_OP_SET_EXP_FEATURE, 0,
4030 &rp, sizeof(rp));
4031
4032 if (changed)
4033 exp_ll_privacy_feature_changed(val, hdev, sk);
4034
4035 return err;
4036 }
4037
Marcel Holtmanna10c9072020-05-06 09:57:51 +02004038 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
4039 MGMT_OP_SET_EXP_FEATURE,
4040 MGMT_STATUS_NOT_SUPPORTED);
4041}
4042
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004043#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
4044
4045static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4046 u16 data_len)
4047{
4048 struct mgmt_cp_get_device_flags *cp = data;
4049 struct mgmt_rp_get_device_flags rp;
4050 struct bdaddr_list_with_flags *br_params;
4051 struct hci_conn_params *params;
4052 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4053 u32 current_flags = 0;
4054 u8 status = MGMT_STATUS_INVALID_PARAMS;
4055
4056 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
4057 &cp->addr.bdaddr, cp->addr.type);
4058
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004059 hci_dev_lock(hdev);
4060
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004061 if (cp->addr.type == BDADDR_BREDR) {
4062 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4063 &cp->addr.bdaddr,
4064 cp->addr.type);
4065 if (!br_params)
4066 goto done;
4067
4068 current_flags = br_params->current_flags;
4069 } else {
4070 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4071 le_addr_type(cp->addr.type));
4072
4073 if (!params)
4074 goto done;
4075
4076 current_flags = params->current_flags;
4077 }
4078
4079 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4080 rp.addr.type = cp->addr.type;
4081 rp.supported_flags = cpu_to_le32(supported_flags);
4082 rp.current_flags = cpu_to_le32(current_flags);
4083
4084 status = MGMT_STATUS_SUCCESS;
4085
4086done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004087 hci_dev_unlock(hdev);
4088
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004089 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
4090 &rp, sizeof(rp));
4091}
4092
4093static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
4094 bdaddr_t *bdaddr, u8 bdaddr_type,
4095 u32 supported_flags, u32 current_flags)
4096{
4097 struct mgmt_ev_device_flags_changed ev;
4098
4099 bacpy(&ev.addr.bdaddr, bdaddr);
4100 ev.addr.type = bdaddr_type;
4101 ev.supported_flags = cpu_to_le32(supported_flags);
4102 ev.current_flags = cpu_to_le32(current_flags);
4103
4104 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
4105}
4106
4107static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
4108 u16 len)
4109{
4110 struct mgmt_cp_set_device_flags *cp = data;
4111 struct bdaddr_list_with_flags *br_params;
4112 struct hci_conn_params *params;
4113 u8 status = MGMT_STATUS_INVALID_PARAMS;
4114 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
4115 u32 current_flags = __le32_to_cpu(cp->current_flags);
4116
4117 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
4118 &cp->addr.bdaddr, cp->addr.type,
4119 __le32_to_cpu(current_flags));
4120
4121 if ((supported_flags | current_flags) != supported_flags) {
4122 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
4123 current_flags, supported_flags);
4124 goto done;
4125 }
4126
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004127 hci_dev_lock(hdev);
4128
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004129 if (cp->addr.type == BDADDR_BREDR) {
4130 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
4131 &cp->addr.bdaddr,
4132 cp->addr.type);
4133
4134 if (br_params) {
4135 br_params->current_flags = current_flags;
4136 status = MGMT_STATUS_SUCCESS;
4137 } else {
4138 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
4139 &cp->addr.bdaddr, cp->addr.type);
4140 }
4141 } else {
4142 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4143 le_addr_type(cp->addr.type));
4144 if (params) {
4145 params->current_flags = current_flags;
4146 status = MGMT_STATUS_SUCCESS;
4147 } else {
4148 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4149 &cp->addr.bdaddr,
4150 le_addr_type(cp->addr.type));
4151 }
4152 }
4153
4154done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004155 hci_dev_unlock(hdev);
4156
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004157 if (status == MGMT_STATUS_SUCCESS)
4158 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4159 supported_flags, current_flags);
4160
4161 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4162 &cp->addr, sizeof(cp->addr));
4163}
4164
Miao-chen Choub52729f2020-06-17 16:39:16 +02004165static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4166 u16 handle)
4167{
4168 struct mgmt_ev_adv_monitor_added ev;
4169
4170 ev.monitor_handle = cpu_to_le16(handle);
4171
4172 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4173}
4174
Archie Pusaka66bd0952021-01-22 16:36:13 +08004175void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004176{
Archie Pusaka66bd0952021-01-22 16:36:13 +08004177 struct mgmt_ev_adv_monitor_removed ev;
4178 struct mgmt_pending_cmd *cmd;
4179 struct sock *sk_skip = NULL;
4180 struct mgmt_cp_remove_adv_monitor *cp;
4181
4182 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4183 if (cmd) {
4184 cp = cmd->param;
4185
4186 if (cp->monitor_handle)
4187 sk_skip = cmd->sk;
4188 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004189
4190 ev.monitor_handle = cpu_to_le16(handle);
4191
Archie Pusaka66bd0952021-01-22 16:36:13 +08004192 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004193}
4194
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004195static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4196 void *data, u16 len)
4197{
4198 struct adv_monitor *monitor = NULL;
4199 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
Peilin Yecafd4722020-09-09 03:25:51 -04004200 int handle, err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004201 size_t rp_size = 0;
4202 __u32 supported = 0;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004203 __u32 enabled = 0;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004204 __u16 num_handles = 0;
4205 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4206
4207 BT_DBG("request for %s", hdev->name);
4208
4209 hci_dev_lock(hdev);
4210
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004211 if (msft_monitor_supported(hdev))
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004212 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4213
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004214 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004215 handles[num_handles++] = monitor->handle;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004216
4217 hci_dev_unlock(hdev);
4218
4219 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4220 rp = kmalloc(rp_size, GFP_KERNEL);
4221 if (!rp)
4222 return -ENOMEM;
4223
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004224 /* All supported features are currently enabled */
4225 enabled = supported;
4226
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004227 rp->supported_features = cpu_to_le32(supported);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004228 rp->enabled_features = cpu_to_le32(enabled);
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004229 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4230 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4231 rp->num_handles = cpu_to_le16(num_handles);
4232 if (num_handles)
4233 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4234
Peilin Yecafd4722020-09-09 03:25:51 -04004235 err = mgmt_cmd_complete(sk, hdev->id,
4236 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4237 MGMT_STATUS_SUCCESS, rp, rp_size);
4238
4239 kfree(rp);
4240
4241 return err;
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004242}
4243
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004244int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
Miao-chen Choub1395532020-06-17 16:39:14 +02004245{
Miao-chen Choub1395532020-06-17 16:39:14 +02004246 struct mgmt_rp_add_adv_patterns_monitor rp;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004247 struct mgmt_pending_cmd *cmd;
4248 struct adv_monitor *monitor;
4249 int err = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004250
4251 hci_dev_lock(hdev);
4252
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004253 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4254 if (!cmd) {
4255 cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4256 if (!cmd)
4257 goto done;
4258 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004259
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004260 monitor = cmd->user_data;
4261 rp.monitor_handle = cpu_to_le16(monitor->handle);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004262
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004263 if (!status) {
4264 mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4265 hdev->adv_monitors_cnt++;
4266 if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4267 monitor->state = ADV_MONITOR_STATE_REGISTERED;
4268 hci_update_background_scan(hdev);
4269 }
4270
4271 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4272 mgmt_status(status), &rp, sizeof(rp));
4273 mgmt_pending_remove(cmd);
4274
4275done:
4276 hci_dev_unlock(hdev);
4277 bt_dev_dbg(hdev, "add monitor %d complete, status %d",
4278 rp.monitor_handle, status);
4279
4280 return err;
4281}
4282
4283static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4284 struct adv_monitor *m, u8 status,
4285 void *data, u16 len, u16 op)
4286{
4287 struct mgmt_rp_add_adv_patterns_monitor rp;
4288 struct mgmt_pending_cmd *cmd;
4289 int err;
4290 bool pending;
4291
4292 hci_dev_lock(hdev);
4293
4294 if (status)
4295 goto unlock;
4296
4297 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4298 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4299 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4300 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4301 status = MGMT_STATUS_BUSY;
Miao-chen Choub1395532020-06-17 16:39:14 +02004302 goto unlock;
4303 }
4304
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004305 cmd = mgmt_pending_add(sk, op, hdev, data, len);
4306 if (!cmd) {
4307 status = MGMT_STATUS_NO_RESOURCES;
4308 goto unlock;
4309 }
4310
Howard Chungb1810fe2021-02-03 15:09:29 +08004311 cmd->user_data = m;
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004312 pending = hci_add_adv_monitor(hdev, m, &err);
4313 if (err) {
4314 if (err == -ENOSPC || err == -ENOMEM)
4315 status = MGMT_STATUS_NO_RESOURCES;
4316 else if (err == -EINVAL)
4317 status = MGMT_STATUS_INVALID_PARAMS;
4318 else
4319 status = MGMT_STATUS_FAILED;
4320
4321 mgmt_pending_remove(cmd);
4322 goto unlock;
4323 }
4324
4325 if (!pending) {
4326 mgmt_pending_remove(cmd);
4327 rp.monitor_handle = cpu_to_le16(m->handle);
Miao-chen Choub52729f2020-06-17 16:39:16 +02004328 mgmt_adv_monitor_added(sk, hdev, m->handle);
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004329 m->state = ADV_MONITOR_STATE_REGISTERED;
4330 hdev->adv_monitors_cnt++;
4331
4332 hci_dev_unlock(hdev);
4333 return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4334 &rp, sizeof(rp));
4335 }
Miao-chen Choub52729f2020-06-17 16:39:16 +02004336
Miao-chen Choub1395532020-06-17 16:39:14 +02004337 hci_dev_unlock(hdev);
4338
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004339 return 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004340
4341unlock:
Archie Pusaka66bd0952021-01-22 16:36:13 +08004342 hci_free_adv_monitor(hdev, m);
Miao-chen Choub1395532020-06-17 16:39:14 +02004343 hci_dev_unlock(hdev);
Archie Pusakab4a221e2021-01-22 16:36:11 +08004344 return mgmt_cmd_status(sk, hdev->id, op, status);
4345}
4346
4347static void parse_adv_monitor_rssi(struct adv_monitor *m,
4348 struct mgmt_adv_rssi_thresholds *rssi)
4349{
4350 if (rssi) {
4351 m->rssi.low_threshold = rssi->low_threshold;
4352 m->rssi.low_threshold_timeout =
4353 __le16_to_cpu(rssi->low_threshold_timeout);
4354 m->rssi.high_threshold = rssi->high_threshold;
4355 m->rssi.high_threshold_timeout =
4356 __le16_to_cpu(rssi->high_threshold_timeout);
4357 m->rssi.sampling_period = rssi->sampling_period;
4358 } else {
4359 /* Default values. These numbers are the least constricting
4360 * parameters for MSFT API to work, so it behaves as if there
4361 * are no rssi parameter to consider. May need to be changed
4362 * if other API are to be supported.
4363 */
4364 m->rssi.low_threshold = -127;
4365 m->rssi.low_threshold_timeout = 60;
4366 m->rssi.high_threshold = -127;
4367 m->rssi.high_threshold_timeout = 0;
4368 m->rssi.sampling_period = 0;
4369 }
4370}
4371
4372static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
4373 struct mgmt_adv_pattern *patterns)
4374{
4375 u8 offset = 0, length = 0;
4376 struct adv_pattern *p = NULL;
Archie Pusakab4a221e2021-01-22 16:36:11 +08004377 int i;
4378
4379 for (i = 0; i < pattern_count; i++) {
Archie Pusakab4a221e2021-01-22 16:36:11 +08004380 offset = patterns[i].offset;
4381 length = patterns[i].length;
4382 if (offset >= HCI_MAX_AD_LENGTH ||
4383 length > HCI_MAX_AD_LENGTH ||
4384 (offset + length) > HCI_MAX_AD_LENGTH)
4385 return MGMT_STATUS_INVALID_PARAMS;
4386
4387 p = kmalloc(sizeof(*p), GFP_KERNEL);
4388 if (!p)
4389 return MGMT_STATUS_NO_RESOURCES;
4390
4391 p->ad_type = patterns[i].ad_type;
4392 p->offset = patterns[i].offset;
4393 p->length = patterns[i].length;
4394 memcpy(p->value, patterns[i].value, p->length);
4395
4396 INIT_LIST_HEAD(&p->list);
4397 list_add(&p->list, &m->patterns);
4398 }
4399
Archie Pusakab4a221e2021-01-22 16:36:11 +08004400 return MGMT_STATUS_SUCCESS;
4401}
4402
4403static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4404 void *data, u16 len)
4405{
4406 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4407 struct adv_monitor *m = NULL;
4408 u8 status = MGMT_STATUS_SUCCESS;
4409 size_t expected_size = sizeof(*cp);
4410
4411 BT_DBG("request for %s", hdev->name);
4412
4413 if (len <= sizeof(*cp)) {
4414 status = MGMT_STATUS_INVALID_PARAMS;
4415 goto done;
4416 }
4417
4418 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4419 if (len != expected_size) {
4420 status = MGMT_STATUS_INVALID_PARAMS;
4421 goto done;
4422 }
4423
4424 m = kzalloc(sizeof(*m), GFP_KERNEL);
4425 if (!m) {
4426 status = MGMT_STATUS_NO_RESOURCES;
4427 goto done;
4428 }
4429
4430 INIT_LIST_HEAD(&m->patterns);
4431
4432 parse_adv_monitor_rssi(m, NULL);
4433 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4434
4435done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004436 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004437 MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
4438}
4439
4440static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
4441 void *data, u16 len)
4442{
4443 struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = data;
4444 struct adv_monitor *m = NULL;
4445 u8 status = MGMT_STATUS_SUCCESS;
4446 size_t expected_size = sizeof(*cp);
4447
4448 BT_DBG("request for %s", hdev->name);
4449
4450 if (len <= sizeof(*cp)) {
4451 status = MGMT_STATUS_INVALID_PARAMS;
4452 goto done;
4453 }
4454
4455 expected_size += cp->pattern_count * sizeof(struct mgmt_adv_pattern);
4456 if (len != expected_size) {
4457 status = MGMT_STATUS_INVALID_PARAMS;
4458 goto done;
4459 }
4460
4461 m = kzalloc(sizeof(*m), GFP_KERNEL);
4462 if (!m) {
4463 status = MGMT_STATUS_NO_RESOURCES;
4464 goto done;
4465 }
4466
4467 INIT_LIST_HEAD(&m->patterns);
4468
4469 parse_adv_monitor_rssi(m, &cp->rssi);
4470 status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
4471
4472done:
Archie Pusakaa2a4ded2021-01-22 16:36:12 +08004473 return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
Archie Pusakab4a221e2021-01-22 16:36:11 +08004474 MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
Miao-chen Choub1395532020-06-17 16:39:14 +02004475}
4476
Archie Pusaka66bd0952021-01-22 16:36:13 +08004477int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4478{
4479 struct mgmt_rp_remove_adv_monitor rp;
4480 struct mgmt_cp_remove_adv_monitor *cp;
4481 struct mgmt_pending_cmd *cmd;
4482 int err = 0;
4483
4484 hci_dev_lock(hdev);
4485
4486 cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4487 if (!cmd)
4488 goto done;
4489
4490 cp = cmd->param;
4491 rp.monitor_handle = cp->monitor_handle;
4492
4493 if (!status)
4494 hci_update_background_scan(hdev);
4495
4496 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4497 mgmt_status(status), &rp, sizeof(rp));
4498 mgmt_pending_remove(cmd);
4499
4500done:
4501 hci_dev_unlock(hdev);
4502 bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
4503 rp.monitor_handle, status);
4504
4505 return err;
4506}
4507
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004508static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4509 void *data, u16 len)
4510{
4511 struct mgmt_cp_remove_adv_monitor *cp = data;
4512 struct mgmt_rp_remove_adv_monitor rp;
Archie Pusaka66bd0952021-01-22 16:36:13 +08004513 struct mgmt_pending_cmd *cmd;
4514 u16 handle = __le16_to_cpu(cp->monitor_handle);
4515 int err, status;
4516 bool pending;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004517
4518 BT_DBG("request for %s", hdev->name);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004519 rp.monitor_handle = cp->monitor_handle;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004520
4521 hci_dev_lock(hdev);
4522
Archie Pusaka66bd0952021-01-22 16:36:13 +08004523 if (pending_find(MGMT_OP_SET_LE, hdev) ||
4524 pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4525 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4526 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4527 status = MGMT_STATUS_BUSY;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004528 goto unlock;
4529 }
4530
Archie Pusaka66bd0952021-01-22 16:36:13 +08004531 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4532 if (!cmd) {
4533 status = MGMT_STATUS_NO_RESOURCES;
4534 goto unlock;
4535 }
4536
4537 if (handle)
4538 pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4539 else
4540 pending = hci_remove_all_adv_monitor(hdev, &err);
4541
4542 if (err) {
4543 mgmt_pending_remove(cmd);
4544
4545 if (err == -ENOENT)
4546 status = MGMT_STATUS_INVALID_INDEX;
4547 else
4548 status = MGMT_STATUS_FAILED;
4549
4550 goto unlock;
4551 }
4552
4553 /* monitor can be removed without forwarding request to controller */
4554 if (!pending) {
4555 mgmt_pending_remove(cmd);
4556 hci_dev_unlock(hdev);
4557
4558 return mgmt_cmd_complete(sk, hdev->id,
4559 MGMT_OP_REMOVE_ADV_MONITOR,
4560 MGMT_STATUS_SUCCESS,
4561 &rp, sizeof(rp));
4562 }
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004563
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004564 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004565 return 0;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004566
4567unlock:
4568 hci_dev_unlock(hdev);
Archie Pusaka66bd0952021-01-22 16:36:13 +08004569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4570 status);
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004571}
4572
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004573static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4574 u16 opcode, struct sk_buff *skb)
4575{
4576 struct mgmt_rp_read_local_oob_data mgmt_rp;
4577 size_t rp_size = sizeof(mgmt_rp);
4578 struct mgmt_pending_cmd *cmd;
4579
Marcel Holtmann181d6952020-05-06 09:57:47 +02004580 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004581
4582 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4583 if (!cmd)
4584 return;
4585
4586 if (status || !skb) {
4587 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4588 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4589 goto remove;
4590 }
4591
4592 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4593
4594 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4595 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4596
4597 if (skb->len < sizeof(*rp)) {
4598 mgmt_cmd_status(cmd->sk, hdev->id,
4599 MGMT_OP_READ_LOCAL_OOB_DATA,
4600 MGMT_STATUS_FAILED);
4601 goto remove;
4602 }
4603
4604 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4605 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4606
4607 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4608 } else {
4609 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4610
4611 if (skb->len < sizeof(*rp)) {
4612 mgmt_cmd_status(cmd->sk, hdev->id,
4613 MGMT_OP_READ_LOCAL_OOB_DATA,
4614 MGMT_STATUS_FAILED);
4615 goto remove;
4616 }
4617
4618 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4619 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4620
4621 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4622 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4623 }
4624
4625 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4626 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4627
4628remove:
4629 mgmt_pending_remove(cmd);
4630}
4631
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004632static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004633 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004634{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004635 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004636 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004637 int err;
4638
Marcel Holtmann181d6952020-05-06 09:57:47 +02004639 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004641 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004642
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004643 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004644 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4645 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004646 goto unlock;
4647 }
4648
Andre Guedes9a1a1992012-07-24 15:03:48 -03004649 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004650 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4651 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004652 goto unlock;
4653 }
4654
Johan Hedberg333ae952015-03-17 13:48:47 +02004655 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004656 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4657 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004658 goto unlock;
4659 }
4660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004661 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004662 if (!cmd) {
4663 err = -ENOMEM;
4664 goto unlock;
4665 }
4666
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004667 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004668
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004669 if (bredr_sc_enabled(hdev))
4670 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4671 else
4672 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4673
4674 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004675 if (err < 0)
4676 mgmt_pending_remove(cmd);
4677
4678unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004679 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004680 return err;
4681}
4682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004683static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004684 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004685{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004686 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004687 int err;
4688
Marcel Holtmann181d6952020-05-06 09:57:47 +02004689 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004690
Johan Hedberg5d57e792015-01-23 10:10:38 +02004691 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004692 return mgmt_cmd_complete(sk, hdev->id,
4693 MGMT_OP_ADD_REMOTE_OOB_DATA,
4694 MGMT_STATUS_INVALID_PARAMS,
4695 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004697 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004698
Marcel Holtmannec109112014-01-10 02:07:30 -08004699 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4700 struct mgmt_cp_add_remote_oob_data *cp = data;
4701 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004702
Johan Hedbergc19a4952014-11-17 20:52:19 +02004703 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004704 err = mgmt_cmd_complete(sk, hdev->id,
4705 MGMT_OP_ADD_REMOTE_OOB_DATA,
4706 MGMT_STATUS_INVALID_PARAMS,
4707 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004708 goto unlock;
4709 }
4710
Marcel Holtmannec109112014-01-10 02:07:30 -08004711 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004712 cp->addr.type, cp->hash,
4713 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004714 if (err < 0)
4715 status = MGMT_STATUS_FAILED;
4716 else
4717 status = MGMT_STATUS_SUCCESS;
4718
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004719 err = mgmt_cmd_complete(sk, hdev->id,
4720 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4721 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004722 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4723 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004724 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004725 u8 status;
4726
Johan Hedberg86df9202014-10-26 20:52:27 +01004727 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004728 /* Enforce zero-valued 192-bit parameters as
4729 * long as legacy SMP OOB isn't implemented.
4730 */
4731 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4732 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004733 err = mgmt_cmd_complete(sk, hdev->id,
4734 MGMT_OP_ADD_REMOTE_OOB_DATA,
4735 MGMT_STATUS_INVALID_PARAMS,
4736 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004737 goto unlock;
4738 }
4739
Johan Hedberg86df9202014-10-26 20:52:27 +01004740 rand192 = NULL;
4741 hash192 = NULL;
4742 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004743 /* In case one of the P-192 values is set to zero,
4744 * then just disable OOB data for P-192.
4745 */
4746 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4747 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4748 rand192 = NULL;
4749 hash192 = NULL;
4750 } else {
4751 rand192 = cp->rand192;
4752 hash192 = cp->hash192;
4753 }
4754 }
4755
4756 /* In case one of the P-256 values is set to zero, then just
4757 * disable OOB data for P-256.
4758 */
4759 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4760 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4761 rand256 = NULL;
4762 hash256 = NULL;
4763 } else {
4764 rand256 = cp->rand256;
4765 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004766 }
4767
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004768 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004769 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004770 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004771 if (err < 0)
4772 status = MGMT_STATUS_FAILED;
4773 else
4774 status = MGMT_STATUS_SUCCESS;
4775
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004776 err = mgmt_cmd_complete(sk, hdev->id,
4777 MGMT_OP_ADD_REMOTE_OOB_DATA,
4778 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004779 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004780 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4781 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004782 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4783 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004784 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004785
Johan Hedbergc19a4952014-11-17 20:52:19 +02004786unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004787 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004788 return err;
4789}
4790
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004791static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004792 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004793{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004794 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004795 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004796 int err;
4797
Marcel Holtmann181d6952020-05-06 09:57:47 +02004798 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004799
Johan Hedbergc19a4952014-11-17 20:52:19 +02004800 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004801 return mgmt_cmd_complete(sk, hdev->id,
4802 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4803 MGMT_STATUS_INVALID_PARAMS,
4804 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004806 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004807
Johan Hedbergeedbd582014-11-15 09:34:23 +02004808 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4809 hci_remote_oob_data_clear(hdev);
4810 status = MGMT_STATUS_SUCCESS;
4811 goto done;
4812 }
4813
Johan Hedberg6928a922014-10-26 20:46:09 +01004814 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004815 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004816 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004817 else
Szymon Janca6785be2012-12-13 15:11:21 +01004818 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004819
Johan Hedbergeedbd582014-11-15 09:34:23 +02004820done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004821 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4822 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004824 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004825 return err;
4826}
4827
Johan Hedberge68f0722015-11-11 08:30:30 +02004828void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004829{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004830 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004831
Marcel Holtmann181d6952020-05-06 09:57:47 +02004832 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004833
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004834 hci_dev_lock(hdev);
4835
Johan Hedberg333ae952015-03-17 13:48:47 +02004836 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004837 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004838 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004839
Johan Hedberg78b781c2016-01-05 13:19:32 +02004840 if (!cmd)
4841 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4842
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004843 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004844 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004845 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004846 }
4847
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004848 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004849
4850 /* Handle suspend notifier */
4851 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4852 hdev->suspend_tasks)) {
4853 bt_dev_dbg(hdev, "Unpaused discovery");
4854 wake_up(&hdev->suspend_wait_q);
4855 }
Andre Guedes7c307722013-04-30 15:29:28 -03004856}
4857
Johan Hedberg591752a2015-11-11 08:11:24 +02004858static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4859 uint8_t *mgmt_status)
4860{
4861 switch (type) {
4862 case DISCOV_TYPE_LE:
4863 *mgmt_status = mgmt_le_support(hdev);
4864 if (*mgmt_status)
4865 return false;
4866 break;
4867 case DISCOV_TYPE_INTERLEAVED:
4868 *mgmt_status = mgmt_le_support(hdev);
4869 if (*mgmt_status)
4870 return false;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05004871 fallthrough;
Johan Hedberg591752a2015-11-11 08:11:24 +02004872 case DISCOV_TYPE_BREDR:
4873 *mgmt_status = mgmt_bredr_support(hdev);
4874 if (*mgmt_status)
4875 return false;
4876 break;
4877 default:
4878 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4879 return false;
4880 }
4881
4882 return true;
4883}
4884
Johan Hedberg78b781c2016-01-05 13:19:32 +02004885static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4886 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004887{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004888 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004889 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004890 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004891 int err;
4892
Marcel Holtmann181d6952020-05-06 09:57:47 +02004893 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004894
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004895 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004896
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004897 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004898 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004899 MGMT_STATUS_NOT_POWERED,
4900 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004901 goto failed;
4902 }
4903
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004904 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004905 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004906 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4907 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004908 goto failed;
4909 }
4910
Johan Hedberg591752a2015-11-11 08:11:24 +02004911 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004912 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4913 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004914 goto failed;
4915 }
4916
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004917 /* Can't start discovery when it is paused */
4918 if (hdev->discovery_paused) {
4919 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4920 &cp->type, sizeof(cp->type));
4921 goto failed;
4922 }
4923
Marcel Holtmann22078802014-12-05 11:45:22 +01004924 /* Clear the discovery filter first to free any previously
4925 * allocated memory for the UUID list.
4926 */
4927 hci_discovery_filter_clear(hdev);
4928
Andre Guedes4aab14e2012-02-17 20:39:36 -03004929 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004930 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004931 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4932 hdev->discovery.limited = true;
4933 else
4934 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004935
Johan Hedberg78b781c2016-01-05 13:19:32 +02004936 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004937 if (!cmd) {
4938 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004939 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004940 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004941
Johan Hedberge68f0722015-11-11 08:30:30 +02004942 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004943
4944 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004945 queue_work(hdev->req_workqueue, &hdev->discov_update);
4946 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004947
4948failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004949 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004950 return err;
4951}
4952
Johan Hedberg78b781c2016-01-05 13:19:32 +02004953static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4954 void *data, u16 len)
4955{
4956 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4957 data, len);
4958}
4959
4960static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4961 void *data, u16 len)
4962{
4963 return start_discovery_internal(sk, hdev,
4964 MGMT_OP_START_LIMITED_DISCOVERY,
4965 data, len);
4966}
4967
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004968static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4969 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004970{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004971 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4972 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004973}
4974
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004975static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4976 void *data, u16 len)
4977{
4978 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004979 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004980 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4981 u16 uuid_count, expected_len;
4982 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004983 int err;
4984
Marcel Holtmann181d6952020-05-06 09:57:47 +02004985 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004986
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004987 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004988
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004989 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004990 err = mgmt_cmd_complete(sk, hdev->id,
4991 MGMT_OP_START_SERVICE_DISCOVERY,
4992 MGMT_STATUS_NOT_POWERED,
4993 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004994 goto failed;
4995 }
4996
4997 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004998 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004999 err = mgmt_cmd_complete(sk, hdev->id,
5000 MGMT_OP_START_SERVICE_DISCOVERY,
5001 MGMT_STATUS_BUSY, &cp->type,
5002 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005003 goto failed;
5004 }
5005
Abhishek Pandit-Subedi36211f72020-12-17 15:04:08 -08005006 if (hdev->discovery_paused) {
5007 err = mgmt_cmd_complete(sk, hdev->id,
5008 MGMT_OP_START_SERVICE_DISCOVERY,
5009 MGMT_STATUS_BUSY, &cp->type,
5010 sizeof(cp->type));
5011 goto failed;
5012 }
5013
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005014 uuid_count = __le16_to_cpu(cp->uuid_count);
5015 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005016 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
5017 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005018 err = mgmt_cmd_complete(sk, hdev->id,
5019 MGMT_OP_START_SERVICE_DISCOVERY,
5020 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5021 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005022 goto failed;
5023 }
5024
5025 expected_len = sizeof(*cp) + uuid_count * 16;
5026 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005027 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
5028 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005029 err = mgmt_cmd_complete(sk, hdev->id,
5030 MGMT_OP_START_SERVICE_DISCOVERY,
5031 MGMT_STATUS_INVALID_PARAMS, &cp->type,
5032 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005033 goto failed;
5034 }
5035
Johan Hedberg591752a2015-11-11 08:11:24 +02005036 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
5037 err = mgmt_cmd_complete(sk, hdev->id,
5038 MGMT_OP_START_SERVICE_DISCOVERY,
5039 status, &cp->type, sizeof(cp->type));
5040 goto failed;
5041 }
5042
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005043 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02005044 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005045 if (!cmd) {
5046 err = -ENOMEM;
5047 goto failed;
5048 }
5049
Johan Hedberg2922a942014-12-05 13:36:06 +02005050 cmd->cmd_complete = service_discovery_cmd_complete;
5051
Marcel Holtmann22078802014-12-05 11:45:22 +01005052 /* Clear the discovery filter first to free any previously
5053 * allocated memory for the UUID list.
5054 */
5055 hci_discovery_filter_clear(hdev);
5056
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08005057 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005058 hdev->discovery.type = cp->type;
5059 hdev->discovery.rssi = cp->rssi;
5060 hdev->discovery.uuid_count = uuid_count;
5061
5062 if (uuid_count > 0) {
5063 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
5064 GFP_KERNEL);
5065 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005066 err = mgmt_cmd_complete(sk, hdev->id,
5067 MGMT_OP_START_SERVICE_DISCOVERY,
5068 MGMT_STATUS_FAILED,
5069 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005070 mgmt_pending_remove(cmd);
5071 goto failed;
5072 }
5073 }
5074
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005075 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02005076 queue_work(hdev->req_workqueue, &hdev->discov_update);
5077 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01005078
5079failed:
5080 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03005081 return err;
5082}
5083
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005084void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03005085{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005086 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005087
Marcel Holtmann181d6952020-05-06 09:57:47 +02005088 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005089
5090 hci_dev_lock(hdev);
5091
Johan Hedberg333ae952015-03-17 13:48:47 +02005092 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005093 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02005094 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01005095 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03005096 }
5097
Andre Guedes0e05bba2013-04-30 15:29:33 -03005098 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005099
5100 /* Handle suspend notifier */
5101 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
5102 bt_dev_dbg(hdev, "Paused discovery");
5103 wake_up(&hdev->suspend_wait_q);
5104 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03005105}
5106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005107static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005108 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04005109{
Johan Hedbergd9306502012-02-20 23:25:18 +02005110 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005111 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04005112 int err;
5113
Marcel Holtmann181d6952020-05-06 09:57:47 +02005114 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04005115
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005116 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005117
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005118 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005119 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5120 MGMT_STATUS_REJECTED, &mgmt_cp->type,
5121 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02005122 goto unlock;
5123 }
5124
5125 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005126 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
5127 MGMT_STATUS_INVALID_PARAMS,
5128 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005129 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02005130 }
5131
Johan Hedberg2922a942014-12-05 13:36:06 +02005132 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04005133 if (!cmd) {
5134 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005135 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04005136 }
5137
Johan Hedberg2922a942014-12-05 13:36:06 +02005138 cmd->cmd_complete = generic_cmd_complete;
5139
Johan Hedberg2154d3f2015-11-11 08:30:45 +02005140 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
5141 queue_work(hdev->req_workqueue, &hdev->discov_update);
5142 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04005143
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005144unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005145 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04005146 return err;
5147}
5148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005149static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005150 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02005151{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005152 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005153 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02005154 int err;
5155
Marcel Holtmann181d6952020-05-06 09:57:47 +02005156 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005157
Johan Hedberg561aafb2012-01-04 13:31:59 +02005158 hci_dev_lock(hdev);
5159
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005160 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005161 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5162 MGMT_STATUS_FAILED, &cp->addr,
5163 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02005164 goto failed;
5165 }
5166
Johan Hedberga198e7b2012-02-17 14:27:06 +02005167 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005168 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005169 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
5170 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
5171 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005172 goto failed;
5173 }
5174
5175 if (cp->name_known) {
5176 e->name_state = NAME_KNOWN;
5177 list_del(&e->list);
5178 } else {
5179 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02005180 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005181 }
5182
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005183 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
5184 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02005185
5186failed:
5187 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02005188 return err;
5189}
5190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005191static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005192 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005193{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005194 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005195 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005196 int err;
5197
Marcel Holtmann181d6952020-05-06 09:57:47 +02005198 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005199
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005200 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005201 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
5202 MGMT_STATUS_INVALID_PARAMS,
5203 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005205 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005206
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005207 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
5208 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005209 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005210 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005211 goto done;
5212 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005213
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005214 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5215 sk);
5216 status = MGMT_STATUS_SUCCESS;
5217
5218done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005219 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
5220 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005221
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005222 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005223
5224 return err;
5225}
5226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005227static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005228 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03005229{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005230 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005231 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03005232 int err;
5233
Marcel Holtmann181d6952020-05-06 09:57:47 +02005234 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03005235
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005236 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005237 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
5238 MGMT_STATUS_INVALID_PARAMS,
5239 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02005240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005241 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005242
Johan Hedbergdcc36c12014-07-09 12:59:13 +03005243 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
5244 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005245 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005246 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005247 goto done;
5248 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02005249
Johan Hedberg2a8357f2014-07-01 22:09:47 +03005250 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
5251 sk);
5252 status = MGMT_STATUS_SUCCESS;
5253
5254done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005255 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
5256 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03005257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03005258 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03005259
5260 return err;
5261}
5262
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005263static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
5264 u16 len)
5265{
5266 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05005267 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005268 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01005269 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005270
Marcel Holtmann181d6952020-05-06 09:57:47 +02005271 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005272
Szymon Jancc72d4b82012-03-16 16:02:57 +01005273 source = __le16_to_cpu(cp->source);
5274
5275 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02005276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
5277 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01005278
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005279 hci_dev_lock(hdev);
5280
Szymon Jancc72d4b82012-03-16 16:02:57 +01005281 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005282 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
5283 hdev->devid_product = __le16_to_cpu(cp->product);
5284 hdev->devid_version = __le16_to_cpu(cp->version);
5285
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
5287 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005288
Johan Hedberg890ea892013-03-15 17:06:52 -05005289 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02005290 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05005291 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07005292
5293 hci_dev_unlock(hdev);
5294
5295 return err;
5296}
5297
Arman Uguray24b4f382015-03-23 15:57:12 -07005298static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
5299 u16 opcode)
5300{
Marcel Holtmann181d6952020-05-06 09:57:47 +02005301 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07005302}
5303
Marcel Holtmann1904a852015-01-11 13:50:44 -08005304static void set_advertising_complete(struct hci_dev *hdev, u8 status,
5305 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03005306{
5307 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07005308 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02005309 u8 instance;
5310 struct adv_info *adv_instance;
5311 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03005312
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305313 hci_dev_lock(hdev);
5314
Johan Hedberg4375f102013-09-25 13:26:10 +03005315 if (status) {
5316 u8 mgmt_err = mgmt_status(status);
5317
5318 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
5319 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305320 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03005321 }
5322
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005323 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005324 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005325 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005326 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03005327
Johan Hedberg4375f102013-09-25 13:26:10 +03005328 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
5329 &match);
5330
5331 new_settings(hdev, match.sk);
5332
5333 if (match.sk)
5334 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305335
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005336 /* Handle suspend notifier */
5337 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
5338 hdev->suspend_tasks)) {
5339 bt_dev_dbg(hdev, "Paused advertising");
5340 wake_up(&hdev->suspend_wait_q);
5341 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
5342 hdev->suspend_tasks)) {
5343 bt_dev_dbg(hdev, "Unpaused advertising");
5344 wake_up(&hdev->suspend_wait_q);
5345 }
5346
Arman Uguray24b4f382015-03-23 15:57:12 -07005347 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02005348 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07005349 */
5350 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005351 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005352 goto unlock;
5353
Florian Grandel7816b822015-06-18 03:16:45 +02005354 instance = hdev->cur_adv_instance;
5355 if (!instance) {
5356 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5357 struct adv_info, list);
5358 if (!adv_instance)
5359 goto unlock;
5360
5361 instance = adv_instance->instance;
5362 }
5363
Arman Uguray24b4f382015-03-23 15:57:12 -07005364 hci_req_init(&req, hdev);
5365
Johan Hedbergf2252572015-11-18 12:49:20 +02005366 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005367
Florian Grandel7816b822015-06-18 03:16:45 +02005368 if (!err)
5369 err = hci_req_run(&req, enable_advertising_instance);
5370
5371 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005372 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005373
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305374unlock:
5375 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005376}
5377
Marcel Holtmann21b51872013-10-10 09:47:53 -07005378static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5379 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005380{
5381 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005382 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005383 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005384 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005385 int err;
5386
Marcel Holtmann181d6952020-05-06 09:57:47 +02005387 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005388
Johan Hedberge6fe7982013-10-02 15:45:22 +03005389 status = mgmt_le_support(hdev);
5390 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005391 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5392 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005393
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05305394 /* Enabling the experimental LL Privay support disables support for
5395 * advertising.
5396 */
5397 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
5398 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5399 MGMT_STATUS_NOT_SUPPORTED);
5400
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005401 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005402 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5403 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005404
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005405 if (hdev->advertising_paused)
5406 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5407 MGMT_STATUS_BUSY);
5408
Johan Hedberg4375f102013-09-25 13:26:10 +03005409 hci_dev_lock(hdev);
5410
5411 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005412
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005413 /* The following conditions are ones which mean that we should
5414 * not do any HCI communication but directly send a mgmt
5415 * response to user space (after toggling the flag if
5416 * necessary).
5417 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005418 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005419 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5420 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005421 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005422 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005423 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005424 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005425
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005426 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005427 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005428 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005429 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005430 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005431 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005432 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005433 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005434 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005435 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005436 }
5437
5438 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5439 if (err < 0)
5440 goto unlock;
5441
5442 if (changed)
5443 err = new_settings(hdev, sk);
5444
5445 goto unlock;
5446 }
5447
Johan Hedberg333ae952015-03-17 13:48:47 +02005448 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5449 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005450 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5451 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005452 goto unlock;
5453 }
5454
5455 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5456 if (!cmd) {
5457 err = -ENOMEM;
5458 goto unlock;
5459 }
5460
5461 hci_req_init(&req, hdev);
5462
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005463 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005464 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005465 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005466 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005467
Florian Grandel7816b822015-06-18 03:16:45 +02005468 cancel_adv_timeout(hdev);
5469
Arman Uguray24b4f382015-03-23 15:57:12 -07005470 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005471 /* Switch to instance "0" for the Set Advertising setting.
5472 * We cannot use update_[adv|scan_rsp]_data() here as the
5473 * HCI_ADVERTISING flag is not yet set.
5474 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005475 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305476
5477 if (ext_adv_capable(hdev)) {
5478 __hci_req_start_ext_adv(&req, 0x00);
5479 } else {
5480 __hci_req_update_adv_data(&req, 0x00);
5481 __hci_req_update_scan_rsp_data(&req, 0x00);
5482 __hci_req_enable_advertising(&req);
5483 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005484 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005485 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005486 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005487
5488 err = hci_req_run(&req, set_advertising_complete);
5489 if (err < 0)
5490 mgmt_pending_remove(cmd);
5491
5492unlock:
5493 hci_dev_unlock(hdev);
5494 return err;
5495}
5496
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005497static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5498 void *data, u16 len)
5499{
5500 struct mgmt_cp_set_static_address *cp = data;
5501 int err;
5502
Marcel Holtmann181d6952020-05-06 09:57:47 +02005503 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005504
Marcel Holtmann62af4442013-10-02 22:10:32 -07005505 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005506 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5507 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005508
5509 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005510 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5511 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005512
5513 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5514 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005515 return mgmt_cmd_status(sk, hdev->id,
5516 MGMT_OP_SET_STATIC_ADDRESS,
5517 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005518
5519 /* Two most significant bits shall be set */
5520 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005521 return mgmt_cmd_status(sk, hdev->id,
5522 MGMT_OP_SET_STATIC_ADDRESS,
5523 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005524 }
5525
5526 hci_dev_lock(hdev);
5527
5528 bacpy(&hdev->static_addr, &cp->bdaddr);
5529
Marcel Holtmann93690c22015-03-06 10:11:21 -08005530 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5531 if (err < 0)
5532 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005533
Marcel Holtmann93690c22015-03-06 10:11:21 -08005534 err = new_settings(hdev, sk);
5535
5536unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005537 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005538 return err;
5539}
5540
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005541static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5542 void *data, u16 len)
5543{
5544 struct mgmt_cp_set_scan_params *cp = data;
5545 __u16 interval, window;
5546 int err;
5547
Marcel Holtmann181d6952020-05-06 09:57:47 +02005548 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005549
5550 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005551 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5552 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005553
5554 interval = __le16_to_cpu(cp->interval);
5555
5556 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005557 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5558 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005559
5560 window = __le16_to_cpu(cp->window);
5561
5562 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005563 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5564 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005565
Marcel Holtmann899e1072013-10-14 09:55:32 -07005566 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005567 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5568 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005569
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005570 hci_dev_lock(hdev);
5571
5572 hdev->le_scan_interval = interval;
5573 hdev->le_scan_window = window;
5574
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5576 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005577
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005578 /* If background scan is running, restart it so new parameters are
5579 * loaded.
5580 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005581 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005582 hdev->discovery.state == DISCOVERY_STOPPED) {
5583 struct hci_request req;
5584
5585 hci_req_init(&req, hdev);
5586
Sathish Narasimman5c49bcc2020-07-23 18:09:01 +05305587 hci_req_add_le_scan_disable(&req, false);
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005588 hci_req_add_le_passive_scan(&req);
5589
5590 hci_req_run(&req, NULL);
5591 }
5592
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005593 hci_dev_unlock(hdev);
5594
5595 return err;
5596}
5597
Marcel Holtmann1904a852015-01-11 13:50:44 -08005598static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5599 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005600{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005601 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005602
Marcel Holtmann181d6952020-05-06 09:57:47 +02005603 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005604
5605 hci_dev_lock(hdev);
5606
Johan Hedberg333ae952015-03-17 13:48:47 +02005607 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005608 if (!cmd)
5609 goto unlock;
5610
5611 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005612 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5613 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005614 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005615 struct mgmt_mode *cp = cmd->param;
5616
5617 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005618 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005619 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005620 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005621
Johan Hedberg33e38b32013-03-15 17:07:05 -05005622 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5623 new_settings(hdev, cmd->sk);
5624 }
5625
5626 mgmt_pending_remove(cmd);
5627
5628unlock:
5629 hci_dev_unlock(hdev);
5630}
5631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005632static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005633 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005634{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005635 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005636 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005637 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005638 int err;
5639
Marcel Holtmann181d6952020-05-06 09:57:47 +02005640 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005641
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005642 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005643 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005644 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5645 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005646
Johan Hedberga7e80f22013-01-09 16:05:19 +02005647 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005648 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5649 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005650
Antti Julkuf6422ec2011-06-22 13:11:56 +03005651 hci_dev_lock(hdev);
5652
Johan Hedberg333ae952015-03-17 13:48:47 +02005653 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005654 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5655 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005656 goto unlock;
5657 }
5658
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005659 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005660 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5661 hdev);
5662 goto unlock;
5663 }
5664
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005665 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005666 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005667 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5668 hdev);
5669 new_settings(hdev, sk);
5670 goto unlock;
5671 }
5672
Johan Hedberg33e38b32013-03-15 17:07:05 -05005673 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5674 data, len);
5675 if (!cmd) {
5676 err = -ENOMEM;
5677 goto unlock;
5678 }
5679
5680 hci_req_init(&req, hdev);
5681
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005682 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005683
5684 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005685 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005686 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5687 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005688 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005689 }
5690
Johan Hedberg33e38b32013-03-15 17:07:05 -05005691unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005692 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005693
Antti Julkuf6422ec2011-06-22 13:11:56 +03005694 return err;
5695}
5696
Marcel Holtmann1904a852015-01-11 13:50:44 -08005697static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005698{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005699 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005700
Marcel Holtmann181d6952020-05-06 09:57:47 +02005701 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005702
5703 hci_dev_lock(hdev);
5704
Johan Hedberg333ae952015-03-17 13:48:47 +02005705 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005706 if (!cmd)
5707 goto unlock;
5708
5709 if (status) {
5710 u8 mgmt_err = mgmt_status(status);
5711
5712 /* We need to restore the flag if related HCI commands
5713 * failed.
5714 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005715 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005716
Johan Hedberga69e8372015-03-06 21:08:53 +02005717 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005718 } else {
5719 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5720 new_settings(hdev, cmd->sk);
5721 }
5722
5723 mgmt_pending_remove(cmd);
5724
5725unlock:
5726 hci_dev_unlock(hdev);
5727}
5728
5729static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5730{
5731 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005732 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005733 struct hci_request req;
5734 int err;
5735
Marcel Holtmann181d6952020-05-06 09:57:47 +02005736 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005737
5738 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005739 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5740 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005741
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005742 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005743 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5744 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005745
5746 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005747 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5748 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005749
5750 hci_dev_lock(hdev);
5751
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005752 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005753 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5754 goto unlock;
5755 }
5756
5757 if (!hdev_is_powered(hdev)) {
5758 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005759 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5760 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5761 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5762 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5763 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005764 }
5765
Marcel Holtmannce05d602015-03-13 02:11:03 -07005766 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005767
5768 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5769 if (err < 0)
5770 goto unlock;
5771
5772 err = new_settings(hdev, sk);
5773 goto unlock;
5774 }
5775
5776 /* Reject disabling when powered on */
5777 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005778 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5779 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005780 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005781 } else {
5782 /* When configuring a dual-mode controller to operate
5783 * with LE only and using a static address, then switching
5784 * BR/EDR back on is not allowed.
5785 *
5786 * Dual-mode controllers shall operate with the public
5787 * address as its identity address for BR/EDR and LE. So
5788 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005789 *
5790 * The same restrictions applies when secure connections
5791 * has been enabled. For BR/EDR this is a controller feature
5792 * while for LE it is a host stack feature. This means that
5793 * switching BR/EDR back on when secure connections has been
5794 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005795 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005796 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005797 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005798 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005799 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5800 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005801 goto unlock;
5802 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005803 }
5804
Johan Hedberg333ae952015-03-17 13:48:47 +02005805 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005806 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5807 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005808 goto unlock;
5809 }
5810
5811 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5812 if (!cmd) {
5813 err = -ENOMEM;
5814 goto unlock;
5815 }
5816
Johan Hedbergf2252572015-11-18 12:49:20 +02005817 /* We need to flip the bit already here so that
5818 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005819 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005820 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005821
5822 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005823
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005824 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005825 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005826
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005827 /* Since only the advertising data flags will change, there
5828 * is no need to update the scan response data.
5829 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005830 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005831
Johan Hedberg0663ca22013-10-02 13:43:14 +03005832 err = hci_req_run(&req, set_bredr_complete);
5833 if (err < 0)
5834 mgmt_pending_remove(cmd);
5835
5836unlock:
5837 hci_dev_unlock(hdev);
5838 return err;
5839}
5840
Johan Hedberga1443f52015-01-23 15:42:46 +02005841static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5842{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005843 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005844 struct mgmt_mode *cp;
5845
Marcel Holtmann181d6952020-05-06 09:57:47 +02005846 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005847
5848 hci_dev_lock(hdev);
5849
Johan Hedberg333ae952015-03-17 13:48:47 +02005850 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005851 if (!cmd)
5852 goto unlock;
5853
5854 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005855 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5856 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005857 goto remove;
5858 }
5859
5860 cp = cmd->param;
5861
5862 switch (cp->val) {
5863 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005864 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5865 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005866 break;
5867 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005868 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005869 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005870 break;
5871 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005872 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5873 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005874 break;
5875 }
5876
5877 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5878 new_settings(hdev, cmd->sk);
5879
5880remove:
5881 mgmt_pending_remove(cmd);
5882unlock:
5883 hci_dev_unlock(hdev);
5884}
5885
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005886static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5887 void *data, u16 len)
5888{
5889 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005890 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005891 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005892 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005893 int err;
5894
Marcel Holtmann181d6952020-05-06 09:57:47 +02005895 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005896
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005897 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005898 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005899 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5900 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005901
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005902 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005903 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005904 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005905 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5906 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005907
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005908 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005909 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005910 MGMT_STATUS_INVALID_PARAMS);
5911
5912 hci_dev_lock(hdev);
5913
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005914 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005915 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005916 bool changed;
5917
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005918 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005919 changed = !hci_dev_test_and_set_flag(hdev,
5920 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005921 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005922 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005923 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005924 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005925 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005926 changed = hci_dev_test_and_clear_flag(hdev,
5927 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005928 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005929 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005930
5931 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5932 if (err < 0)
5933 goto failed;
5934
5935 if (changed)
5936 err = new_settings(hdev, sk);
5937
5938 goto failed;
5939 }
5940
Johan Hedberg333ae952015-03-17 13:48:47 +02005941 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005942 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5943 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005944 goto failed;
5945 }
5946
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005947 val = !!cp->val;
5948
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005949 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5950 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005951 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5952 goto failed;
5953 }
5954
5955 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5956 if (!cmd) {
5957 err = -ENOMEM;
5958 goto failed;
5959 }
5960
Johan Hedberga1443f52015-01-23 15:42:46 +02005961 hci_req_init(&req, hdev);
5962 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5963 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005964 if (err < 0) {
5965 mgmt_pending_remove(cmd);
5966 goto failed;
5967 }
5968
5969failed:
5970 hci_dev_unlock(hdev);
5971 return err;
5972}
5973
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005974static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5975 void *data, u16 len)
5976{
5977 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005978 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005979 int err;
5980
Marcel Holtmann181d6952020-05-06 09:57:47 +02005981 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005982
Johan Hedbergb97109792014-06-24 14:00:28 +03005983 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005984 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5985 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005986
5987 hci_dev_lock(hdev);
5988
5989 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005990 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005991 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005992 changed = hci_dev_test_and_clear_flag(hdev,
5993 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005994
Johan Hedbergb97109792014-06-24 14:00:28 +03005995 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005996 use_changed = !hci_dev_test_and_set_flag(hdev,
5997 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005998 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005999 use_changed = hci_dev_test_and_clear_flag(hdev,
6000 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03006001
6002 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006003 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03006004 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
6005 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
6006 sizeof(mode), &mode);
6007 }
6008
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08006009 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
6010 if (err < 0)
6011 goto unlock;
6012
6013 if (changed)
6014 err = new_settings(hdev, sk);
6015
6016unlock:
6017 hci_dev_unlock(hdev);
6018 return err;
6019}
6020
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006021static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6022 u16 len)
6023{
6024 struct mgmt_cp_set_privacy *cp = cp_data;
6025 bool changed;
6026 int err;
6027
Marcel Holtmann181d6952020-05-06 09:57:47 +02006028 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006029
6030 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006031 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6032 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006033
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006034 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02006035 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006037
6038 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006039 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
6040 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006041
6042 hci_dev_lock(hdev);
6043
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006044 /* If user space supports this command it is also expected to
6045 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
6046 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006047 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02006048
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006049 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07006050 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006051 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006052 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306053 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006054 if (cp->privacy == 0x02)
6055 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
6056 else
6057 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006058 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006059 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006060 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006061 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05306062 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02006063 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02006064 }
6065
6066 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
6067 if (err < 0)
6068 goto unlock;
6069
6070 if (changed)
6071 err = new_settings(hdev, sk);
6072
6073unlock:
6074 hci_dev_unlock(hdev);
6075 return err;
6076}
6077
Johan Hedberg41edf162014-02-18 10:19:35 +02006078static bool irk_is_valid(struct mgmt_irk_info *irk)
6079{
6080 switch (irk->addr.type) {
6081 case BDADDR_LE_PUBLIC:
6082 return true;
6083
6084 case BDADDR_LE_RANDOM:
6085 /* Two most significant bits shall be set */
6086 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6087 return false;
6088 return true;
6089 }
6090
6091 return false;
6092}
6093
6094static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
6095 u16 len)
6096{
6097 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006098 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
6099 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02006100 u16 irk_count, expected_len;
6101 int i, err;
6102
Marcel Holtmann181d6952020-05-06 09:57:47 +02006103 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02006104
6105 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006106 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6107 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02006108
6109 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006110 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006111 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
6112 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6114 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006115 }
Johan Hedberg41edf162014-02-18 10:19:35 +02006116
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006117 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006118 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006119 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
6120 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006121 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
6122 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006123 }
6124
Marcel Holtmann181d6952020-05-06 09:57:47 +02006125 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02006126
6127 for (i = 0; i < irk_count; i++) {
6128 struct mgmt_irk_info *key = &cp->irks[i];
6129
6130 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006131 return mgmt_cmd_status(sk, hdev->id,
6132 MGMT_OP_LOAD_IRKS,
6133 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02006134 }
6135
6136 hci_dev_lock(hdev);
6137
6138 hci_smp_irks_clear(hdev);
6139
6140 for (i = 0; i < irk_count; i++) {
6141 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02006142
Alain Michaud600a8742020-01-07 00:43:17 +00006143 if (hci_is_blocked_key(hdev,
6144 HCI_BLOCKED_KEY_TYPE_IRK,
6145 irk->val)) {
6146 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
6147 &irk->addr.bdaddr);
6148 continue;
6149 }
6150
Johan Hedberg85813a72015-10-21 18:02:59 +03006151 hci_add_irk(hdev, &irk->addr.bdaddr,
6152 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02006153 BDADDR_ANY);
6154 }
6155
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006156 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02006157
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006158 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02006159
6160 hci_dev_unlock(hdev);
6161
6162 return err;
6163}
6164
Johan Hedberg3f706b72013-01-20 14:27:16 +02006165static bool ltk_is_valid(struct mgmt_ltk_info *key)
6166{
6167 if (key->master != 0x00 && key->master != 0x01)
6168 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08006169
6170 switch (key->addr.type) {
6171 case BDADDR_LE_PUBLIC:
6172 return true;
6173
6174 case BDADDR_LE_RANDOM:
6175 /* Two most significant bits shall be set */
6176 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
6177 return false;
6178 return true;
6179 }
6180
6181 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02006182}
6183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006184static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006185 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006186{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006187 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006188 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
6189 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006190 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006191 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006192
Marcel Holtmann181d6952020-05-06 09:57:47 +02006193 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006194
6195 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006196 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6197 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07006198
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006199 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006200 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006201 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
6202 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006203 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6204 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006205 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006206
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006207 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006208 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006209 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
6210 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006211 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
6212 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006213 }
6214
Marcel Holtmann181d6952020-05-06 09:57:47 +02006215 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006216
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006217 for (i = 0; i < key_count; i++) {
6218 struct mgmt_ltk_info *key = &cp->keys[i];
6219
Johan Hedberg3f706b72013-01-20 14:27:16 +02006220 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02006221 return mgmt_cmd_status(sk, hdev->id,
6222 MGMT_OP_LOAD_LONG_TERM_KEYS,
6223 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02006224 }
6225
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006226 hci_dev_lock(hdev);
6227
6228 hci_smp_ltks_clear(hdev);
6229
6230 for (i = 0; i < key_count; i++) {
6231 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03006232 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006233
Alain Michaud600a8742020-01-07 00:43:17 +00006234 if (hci_is_blocked_key(hdev,
6235 HCI_BLOCKED_KEY_TYPE_LTK,
6236 key->val)) {
6237 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
6238 &key->addr.bdaddr);
6239 continue;
6240 }
6241
Johan Hedberg61b43352014-05-29 19:36:53 +03006242 switch (key->type) {
6243 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006244 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006245 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006246 break;
6247 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03006248 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006249 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03006250 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006251 case MGMT_LTK_P256_UNAUTH:
6252 authenticated = 0x00;
6253 type = SMP_LTK_P256;
6254 break;
6255 case MGMT_LTK_P256_AUTH:
6256 authenticated = 0x01;
6257 type = SMP_LTK_P256;
6258 break;
6259 case MGMT_LTK_P256_DEBUG:
6260 authenticated = 0x00;
6261 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva19186c72020-07-08 15:18:23 -05006262 fallthrough;
Johan Hedberg61b43352014-05-29 19:36:53 +03006263 default:
6264 continue;
6265 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006266
Johan Hedberg85813a72015-10-21 18:02:59 +03006267 hci_add_ltk(hdev, &key->addr.bdaddr,
6268 le_addr_type(key->addr.type), type, authenticated,
6269 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006270 }
6271
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006272 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006273 NULL, 0);
6274
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006275 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006276
Johan Hedberg715a5bf2013-01-09 15:29:34 +02006277 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006278}
6279
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006280static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006281{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006282 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006283 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02006284 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006285
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006286 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006287
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006288 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006289 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006290 rp.tx_power = conn->tx_power;
6291 rp.max_tx_power = conn->max_tx_power;
6292 } else {
6293 rp.rssi = HCI_RSSI_INVALID;
6294 rp.tx_power = HCI_TX_POWER_INVALID;
6295 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006296 }
6297
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006298 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
6299 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006300
6301 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006302 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02006303
6304 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006305}
6306
Marcel Holtmann1904a852015-01-11 13:50:44 -08006307static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
6308 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006309{
6310 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006311 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006312 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006313 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006314 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006315
Marcel Holtmann181d6952020-05-06 09:57:47 +02006316 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006317
6318 hci_dev_lock(hdev);
6319
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006320 /* Commands sent in request are either Read RSSI or Read Transmit Power
6321 * Level so we check which one was last sent to retrieve connection
6322 * handle. Both commands have handle as first parameter so it's safe to
6323 * cast data on the same command struct.
6324 *
6325 * First command sent is always Read RSSI and we fail only if it fails.
6326 * In other case we simply override error to indicate success as we
6327 * already remembered if TX power value is actually valid.
6328 */
6329 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
6330 if (!cp) {
6331 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006332 status = MGMT_STATUS_SUCCESS;
6333 } else {
6334 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006335 }
6336
6337 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006338 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006339 goto unlock;
6340 }
6341
6342 handle = __le16_to_cpu(cp->handle);
6343 conn = hci_conn_hash_lookup_handle(hdev, handle);
6344 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006345 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
6346 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006347 goto unlock;
6348 }
6349
Johan Hedberg333ae952015-03-17 13:48:47 +02006350 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006351 if (!cmd)
6352 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006353
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006354 cmd->cmd_complete(cmd, status);
6355 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006356
6357unlock:
6358 hci_dev_unlock(hdev);
6359}
6360
6361static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6362 u16 len)
6363{
6364 struct mgmt_cp_get_conn_info *cp = data;
6365 struct mgmt_rp_get_conn_info rp;
6366 struct hci_conn *conn;
6367 unsigned long conn_info_age;
6368 int err = 0;
6369
Marcel Holtmann181d6952020-05-06 09:57:47 +02006370 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006371
6372 memset(&rp, 0, sizeof(rp));
6373 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6374 rp.addr.type = cp->addr.type;
6375
6376 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006377 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6378 MGMT_STATUS_INVALID_PARAMS,
6379 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006380
6381 hci_dev_lock(hdev);
6382
6383 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006384 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6385 MGMT_STATUS_NOT_POWERED, &rp,
6386 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006387 goto unlock;
6388 }
6389
6390 if (cp->addr.type == BDADDR_BREDR)
6391 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6392 &cp->addr.bdaddr);
6393 else
6394 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6395
6396 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006397 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6398 MGMT_STATUS_NOT_CONNECTED, &rp,
6399 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006400 goto unlock;
6401 }
6402
Johan Hedberg333ae952015-03-17 13:48:47 +02006403 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006404 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6405 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006406 goto unlock;
6407 }
6408
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006409 /* To avoid client trying to guess when to poll again for information we
6410 * calculate conn info age as random value between min/max set in hdev.
6411 */
6412 conn_info_age = hdev->conn_info_min_age +
6413 prandom_u32_max(hdev->conn_info_max_age -
6414 hdev->conn_info_min_age);
6415
6416 /* Query controller to refresh cached values if they are too old or were
6417 * never read.
6418 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006419 if (time_after(jiffies, conn->conn_info_timestamp +
6420 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006421 !conn->conn_info_timestamp) {
6422 struct hci_request req;
6423 struct hci_cp_read_tx_power req_txp_cp;
6424 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006425 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006426
6427 hci_req_init(&req, hdev);
6428 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6429 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6430 &req_rssi_cp);
6431
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006432 /* For LE links TX power does not change thus we don't need to
6433 * query for it once value is known.
6434 */
6435 if (!bdaddr_type_is_le(cp->addr.type) ||
6436 conn->tx_power == HCI_TX_POWER_INVALID) {
6437 req_txp_cp.handle = cpu_to_le16(conn->handle);
6438 req_txp_cp.type = 0x00;
6439 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6440 sizeof(req_txp_cp), &req_txp_cp);
6441 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006442
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006443 /* Max TX power needs to be read only once per connection */
6444 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6445 req_txp_cp.handle = cpu_to_le16(conn->handle);
6446 req_txp_cp.type = 0x01;
6447 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6448 sizeof(req_txp_cp), &req_txp_cp);
6449 }
6450
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006451 err = hci_req_run(&req, conn_info_refresh_complete);
6452 if (err < 0)
6453 goto unlock;
6454
6455 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6456 data, len);
6457 if (!cmd) {
6458 err = -ENOMEM;
6459 goto unlock;
6460 }
6461
6462 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006463 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006464 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006465
6466 conn->conn_info_timestamp = jiffies;
6467 } else {
6468 /* Cache is valid, just reply with values cached in hci_conn */
6469 rp.rssi = conn->rssi;
6470 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006471 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006472
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006473 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6474 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006475 }
6476
6477unlock:
6478 hci_dev_unlock(hdev);
6479 return err;
6480}
6481
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006482static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006483{
6484 struct hci_conn *conn = cmd->user_data;
6485 struct mgmt_rp_get_clock_info rp;
6486 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006487 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006488
6489 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006490 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006491
6492 if (status)
6493 goto complete;
6494
6495 hdev = hci_dev_get(cmd->index);
6496 if (hdev) {
6497 rp.local_clock = cpu_to_le32(hdev->clock);
6498 hci_dev_put(hdev);
6499 }
6500
6501 if (conn) {
6502 rp.piconet_clock = cpu_to_le32(conn->clock);
6503 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6504 }
6505
6506complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006507 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6508 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006509
6510 if (conn) {
6511 hci_conn_drop(conn);
6512 hci_conn_put(conn);
6513 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006514
6515 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006516}
6517
Marcel Holtmann1904a852015-01-11 13:50:44 -08006518static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006519{
Johan Hedberg95868422014-06-28 17:54:07 +03006520 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006521 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006522 struct hci_conn *conn;
6523
Marcel Holtmann181d6952020-05-06 09:57:47 +02006524 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006525
6526 hci_dev_lock(hdev);
6527
6528 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6529 if (!hci_cp)
6530 goto unlock;
6531
6532 if (hci_cp->which) {
6533 u16 handle = __le16_to_cpu(hci_cp->handle);
6534 conn = hci_conn_hash_lookup_handle(hdev, handle);
6535 } else {
6536 conn = NULL;
6537 }
6538
Johan Hedberg333ae952015-03-17 13:48:47 +02006539 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006540 if (!cmd)
6541 goto unlock;
6542
Johan Hedberg69487372014-12-05 13:36:07 +02006543 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006544 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006545
6546unlock:
6547 hci_dev_unlock(hdev);
6548}
6549
6550static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6551 u16 len)
6552{
6553 struct mgmt_cp_get_clock_info *cp = data;
6554 struct mgmt_rp_get_clock_info rp;
6555 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006556 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006557 struct hci_request req;
6558 struct hci_conn *conn;
6559 int err;
6560
Marcel Holtmann181d6952020-05-06 09:57:47 +02006561 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006562
6563 memset(&rp, 0, sizeof(rp));
6564 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6565 rp.addr.type = cp->addr.type;
6566
6567 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006568 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6569 MGMT_STATUS_INVALID_PARAMS,
6570 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006571
6572 hci_dev_lock(hdev);
6573
6574 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6576 MGMT_STATUS_NOT_POWERED, &rp,
6577 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006578 goto unlock;
6579 }
6580
6581 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6582 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6583 &cp->addr.bdaddr);
6584 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006585 err = mgmt_cmd_complete(sk, hdev->id,
6586 MGMT_OP_GET_CLOCK_INFO,
6587 MGMT_STATUS_NOT_CONNECTED,
6588 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006589 goto unlock;
6590 }
6591 } else {
6592 conn = NULL;
6593 }
6594
6595 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6596 if (!cmd) {
6597 err = -ENOMEM;
6598 goto unlock;
6599 }
6600
Johan Hedberg69487372014-12-05 13:36:07 +02006601 cmd->cmd_complete = clock_info_cmd_complete;
6602
Johan Hedberg95868422014-06-28 17:54:07 +03006603 hci_req_init(&req, hdev);
6604
6605 memset(&hci_cp, 0, sizeof(hci_cp));
6606 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6607
6608 if (conn) {
6609 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006610 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006611
6612 hci_cp.handle = cpu_to_le16(conn->handle);
6613 hci_cp.which = 0x01; /* Piconet clock */
6614 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6615 }
6616
6617 err = hci_req_run(&req, get_clock_info_complete);
6618 if (err < 0)
6619 mgmt_pending_remove(cmd);
6620
6621unlock:
6622 hci_dev_unlock(hdev);
6623 return err;
6624}
6625
Johan Hedberg5a154e62014-12-19 22:26:02 +02006626static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6627{
6628 struct hci_conn *conn;
6629
6630 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6631 if (!conn)
6632 return false;
6633
6634 if (conn->dst_type != type)
6635 return false;
6636
6637 if (conn->state != BT_CONNECTED)
6638 return false;
6639
6640 return true;
6641}
6642
6643/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006644static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006645 u8 addr_type, u8 auto_connect)
6646{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006647 struct hci_conn_params *params;
6648
6649 params = hci_conn_params_add(hdev, addr, addr_type);
6650 if (!params)
6651 return -EIO;
6652
6653 if (params->auto_connect == auto_connect)
6654 return 0;
6655
6656 list_del_init(&params->action);
6657
6658 switch (auto_connect) {
6659 case HCI_AUTO_CONN_DISABLED:
6660 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006661 /* If auto connect is being disabled when we're trying to
6662 * connect to device, keep connecting.
6663 */
6664 if (params->explicit_connect)
6665 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006666 break;
6667 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006668 if (params->explicit_connect)
6669 list_add(&params->action, &hdev->pend_le_conns);
6670 else
6671 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006672 break;
6673 case HCI_AUTO_CONN_DIRECT:
6674 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006675 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006676 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006677 break;
6678 }
6679
6680 params->auto_connect = auto_connect;
6681
Marcel Holtmann181d6952020-05-06 09:57:47 +02006682 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6683 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006684
6685 return 0;
6686}
6687
Marcel Holtmann8afef092014-06-29 22:28:34 +02006688static void device_added(struct sock *sk, struct hci_dev *hdev,
6689 bdaddr_t *bdaddr, u8 type, u8 action)
6690{
6691 struct mgmt_ev_device_added ev;
6692
6693 bacpy(&ev.addr.bdaddr, bdaddr);
6694 ev.addr.type = type;
6695 ev.action = action;
6696
6697 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6698}
6699
Marcel Holtmann2faade52014-06-29 19:44:03 +02006700static int add_device(struct sock *sk, struct hci_dev *hdev,
6701 void *data, u16 len)
6702{
6703 struct mgmt_cp_add_device *cp = data;
6704 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006705 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006706 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006707 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006708
Marcel Holtmann181d6952020-05-06 09:57:47 +02006709 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006710
Johan Hedberg66593582014-07-09 12:59:14 +03006711 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006712 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006713 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6714 MGMT_STATUS_INVALID_PARAMS,
6715 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006716
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006717 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006718 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6719 MGMT_STATUS_INVALID_PARAMS,
6720 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006721
6722 hci_dev_lock(hdev);
6723
Johan Hedberg66593582014-07-09 12:59:14 +03006724 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006725 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006726 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006727 err = mgmt_cmd_complete(sk, hdev->id,
6728 MGMT_OP_ADD_DEVICE,
6729 MGMT_STATUS_INVALID_PARAMS,
6730 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006731 goto unlock;
6732 }
6733
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006734 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6735 &cp->addr.bdaddr,
6736 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006737 if (err)
6738 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006739
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006740 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006741
Johan Hedberg66593582014-07-09 12:59:14 +03006742 goto added;
6743 }
6744
Johan Hedberg85813a72015-10-21 18:02:59 +03006745 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006746
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006747 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006748 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006749 else if (cp->action == 0x01)
6750 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006751 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006752 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006753
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006754 /* Kernel internally uses conn_params with resolvable private
6755 * address, but Add Device allows only identity addresses.
6756 * Make sure it is enforced before calling
6757 * hci_conn_params_lookup.
6758 */
6759 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006760 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6761 MGMT_STATUS_INVALID_PARAMS,
6762 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006763 goto unlock;
6764 }
6765
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006766 /* If the connection parameters don't exist for this device,
6767 * they will be created and configured with defaults.
6768 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006769 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006770 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006771 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6772 MGMT_STATUS_FAILED, &cp->addr,
6773 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006774 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006775 } else {
6776 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6777 addr_type);
6778 if (params)
6779 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006780 }
6781
Johan Hedberg51d7a942015-11-11 08:11:18 +02006782 hci_update_background_scan(hdev);
6783
Johan Hedberg66593582014-07-09 12:59:14 +03006784added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006785 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006786 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6787 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006788
Johan Hedberg51d7a942015-11-11 08:11:18 +02006789 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6790 MGMT_STATUS_SUCCESS, &cp->addr,
6791 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006792
6793unlock:
6794 hci_dev_unlock(hdev);
6795 return err;
6796}
6797
Marcel Holtmann8afef092014-06-29 22:28:34 +02006798static void device_removed(struct sock *sk, struct hci_dev *hdev,
6799 bdaddr_t *bdaddr, u8 type)
6800{
6801 struct mgmt_ev_device_removed ev;
6802
6803 bacpy(&ev.addr.bdaddr, bdaddr);
6804 ev.addr.type = type;
6805
6806 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6807}
6808
Marcel Holtmann2faade52014-06-29 19:44:03 +02006809static int remove_device(struct sock *sk, struct hci_dev *hdev,
6810 void *data, u16 len)
6811{
6812 struct mgmt_cp_remove_device *cp = data;
6813 int err;
6814
Marcel Holtmann181d6952020-05-06 09:57:47 +02006815 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006816
6817 hci_dev_lock(hdev);
6818
6819 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006820 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006821 u8 addr_type;
6822
Johan Hedberg66593582014-07-09 12:59:14 +03006823 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006824 err = mgmt_cmd_complete(sk, hdev->id,
6825 MGMT_OP_REMOVE_DEVICE,
6826 MGMT_STATUS_INVALID_PARAMS,
6827 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006828 goto unlock;
6829 }
6830
Johan Hedberg66593582014-07-09 12:59:14 +03006831 if (cp->addr.type == BDADDR_BREDR) {
6832 err = hci_bdaddr_list_del(&hdev->whitelist,
6833 &cp->addr.bdaddr,
6834 cp->addr.type);
6835 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006836 err = mgmt_cmd_complete(sk, hdev->id,
6837 MGMT_OP_REMOVE_DEVICE,
6838 MGMT_STATUS_INVALID_PARAMS,
6839 &cp->addr,
6840 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006841 goto unlock;
6842 }
6843
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006844 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006845
Johan Hedberg66593582014-07-09 12:59:14 +03006846 device_removed(sk, hdev, &cp->addr.bdaddr,
6847 cp->addr.type);
6848 goto complete;
6849 }
6850
Johan Hedberg85813a72015-10-21 18:02:59 +03006851 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006852
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006853 /* Kernel internally uses conn_params with resolvable private
6854 * address, but Remove Device allows only identity addresses.
6855 * Make sure it is enforced before calling
6856 * hci_conn_params_lookup.
6857 */
6858 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006859 err = mgmt_cmd_complete(sk, hdev->id,
6860 MGMT_OP_REMOVE_DEVICE,
6861 MGMT_STATUS_INVALID_PARAMS,
6862 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006863 goto unlock;
6864 }
6865
Johan Hedbergc71593d2014-07-02 17:37:28 +03006866 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6867 addr_type);
6868 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006869 err = mgmt_cmd_complete(sk, hdev->id,
6870 MGMT_OP_REMOVE_DEVICE,
6871 MGMT_STATUS_INVALID_PARAMS,
6872 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006873 goto unlock;
6874 }
6875
Johan Hedberg679d2b62015-10-16 10:07:52 +03006876 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6877 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006878 err = mgmt_cmd_complete(sk, hdev->id,
6879 MGMT_OP_REMOVE_DEVICE,
6880 MGMT_STATUS_INVALID_PARAMS,
6881 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006882 goto unlock;
6883 }
6884
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006885 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006886 list_del(&params->list);
6887 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006888 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006889
6890 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006891 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006892 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006893 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006894
Marcel Holtmann2faade52014-06-29 19:44:03 +02006895 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006896 err = mgmt_cmd_complete(sk, hdev->id,
6897 MGMT_OP_REMOVE_DEVICE,
6898 MGMT_STATUS_INVALID_PARAMS,
6899 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006900 goto unlock;
6901 }
6902
Johan Hedberg66593582014-07-09 12:59:14 +03006903 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6904 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6905 list_del(&b->list);
6906 kfree(b);
6907 }
6908
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006909 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006910
Johan Hedberg19de0822014-07-06 13:06:51 +03006911 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6912 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6913 continue;
6914 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006915 if (p->explicit_connect) {
6916 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6917 continue;
6918 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006919 list_del(&p->action);
6920 list_del(&p->list);
6921 kfree(p);
6922 }
6923
Marcel Holtmann181d6952020-05-06 09:57:47 +02006924 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006925
Johan Hedberg51d7a942015-11-11 08:11:18 +02006926 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006927 }
6928
Johan Hedberg66593582014-07-09 12:59:14 +03006929complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6931 MGMT_STATUS_SUCCESS, &cp->addr,
6932 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006933unlock:
6934 hci_dev_unlock(hdev);
6935 return err;
6936}
6937
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006938static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6939 u16 len)
6940{
6941 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006942 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6943 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006944 u16 param_count, expected_len;
6945 int i;
6946
6947 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006948 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6949 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006950
6951 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006952 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006953 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6954 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6956 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006957 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006958
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006959 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006960 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006961 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6962 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006963 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6964 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006965 }
6966
Marcel Holtmann181d6952020-05-06 09:57:47 +02006967 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006968
6969 hci_dev_lock(hdev);
6970
6971 hci_conn_params_clear_disabled(hdev);
6972
6973 for (i = 0; i < param_count; i++) {
6974 struct mgmt_conn_param *param = &cp->params[i];
6975 struct hci_conn_params *hci_param;
6976 u16 min, max, latency, timeout;
6977 u8 addr_type;
6978
Marcel Holtmann181d6952020-05-06 09:57:47 +02006979 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6980 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006981
6982 if (param->addr.type == BDADDR_LE_PUBLIC) {
6983 addr_type = ADDR_LE_DEV_PUBLIC;
6984 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6985 addr_type = ADDR_LE_DEV_RANDOM;
6986 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006987 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006988 continue;
6989 }
6990
6991 min = le16_to_cpu(param->min_interval);
6992 max = le16_to_cpu(param->max_interval);
6993 latency = le16_to_cpu(param->latency);
6994 timeout = le16_to_cpu(param->timeout);
6995
Marcel Holtmann181d6952020-05-06 09:57:47 +02006996 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6997 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006998
6999 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007000 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007001 continue;
7002 }
7003
7004 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
7005 addr_type);
7006 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01007007 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007008 continue;
7009 }
7010
7011 hci_param->conn_min_interval = min;
7012 hci_param->conn_max_interval = max;
7013 hci_param->conn_latency = latency;
7014 hci_param->supervision_timeout = timeout;
7015 }
7016
7017 hci_dev_unlock(hdev);
7018
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007019 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
7020 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03007021}
7022
Marcel Holtmanndbece372014-07-04 18:11:55 +02007023static int set_external_config(struct sock *sk, struct hci_dev *hdev,
7024 void *data, u16 len)
7025{
7026 struct mgmt_cp_set_external_config *cp = data;
7027 bool changed;
7028 int err;
7029
Marcel Holtmann181d6952020-05-06 09:57:47 +02007030 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007031
7032 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007033 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7034 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007035
7036 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02007037 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7038 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007039
7040 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02007041 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
7042 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007043
7044 hci_dev_lock(hdev);
7045
7046 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07007047 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007048 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007049 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02007050
7051 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
7052 if (err < 0)
7053 goto unlock;
7054
7055 if (!changed)
7056 goto unlock;
7057
Marcel Holtmannf4537c02014-07-04 19:06:23 +02007058 err = new_options(hdev, sk);
7059
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007060 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02007061 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007062
Marcel Holtmann516018a2015-03-13 02:11:04 -07007063 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007064 hci_dev_set_flag(hdev, HCI_CONFIG);
7065 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007066
7067 queue_work(hdev->req_workqueue, &hdev->power_on);
7068 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02007069 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02007070 mgmt_index_added(hdev);
7071 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02007072 }
7073
7074unlock:
7075 hci_dev_unlock(hdev);
7076 return err;
7077}
7078
Marcel Holtmann9713c172014-07-06 12:11:15 +02007079static int set_public_address(struct sock *sk, struct hci_dev *hdev,
7080 void *data, u16 len)
7081{
7082 struct mgmt_cp_set_public_address *cp = data;
7083 bool changed;
7084 int err;
7085
Marcel Holtmann181d6952020-05-06 09:57:47 +02007086 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007087
7088 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02007089 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7090 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007091
7092 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02007093 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7094 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007095
7096 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02007097 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
7098 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007099
7100 hci_dev_lock(hdev);
7101
7102 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
7103 bacpy(&hdev->public_addr, &cp->bdaddr);
7104
7105 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
7106 if (err < 0)
7107 goto unlock;
7108
7109 if (!changed)
7110 goto unlock;
7111
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007112 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02007113 err = new_options(hdev, sk);
7114
7115 if (is_configured(hdev)) {
7116 mgmt_index_removed(hdev);
7117
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007118 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007119
Marcel Holtmanna1536da2015-03-13 02:11:01 -07007120 hci_dev_set_flag(hdev, HCI_CONFIG);
7121 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02007122
7123 queue_work(hdev->req_workqueue, &hdev->power_on);
7124 }
7125
7126unlock:
7127 hci_dev_unlock(hdev);
7128 return err;
7129}
7130
Johan Hedberg40f66c02015-04-07 21:52:22 +03007131static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
7132 u16 opcode, struct sk_buff *skb)
7133{
7134 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
7135 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
7136 u8 *h192, *r192, *h256, *r256;
7137 struct mgmt_pending_cmd *cmd;
7138 u16 eir_len;
7139 int err;
7140
Marcel Holtmann181d6952020-05-06 09:57:47 +02007141 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03007142
7143 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
7144 if (!cmd)
7145 return;
7146
7147 mgmt_cp = cmd->param;
7148
7149 if (status) {
7150 status = mgmt_status(status);
7151 eir_len = 0;
7152
7153 h192 = NULL;
7154 r192 = NULL;
7155 h256 = NULL;
7156 r256 = NULL;
7157 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
7158 struct hci_rp_read_local_oob_data *rp;
7159
7160 if (skb->len != sizeof(*rp)) {
7161 status = MGMT_STATUS_FAILED;
7162 eir_len = 0;
7163 } else {
7164 status = MGMT_STATUS_SUCCESS;
7165 rp = (void *)skb->data;
7166
7167 eir_len = 5 + 18 + 18;
7168 h192 = rp->hash;
7169 r192 = rp->rand;
7170 h256 = NULL;
7171 r256 = NULL;
7172 }
7173 } else {
7174 struct hci_rp_read_local_oob_ext_data *rp;
7175
7176 if (skb->len != sizeof(*rp)) {
7177 status = MGMT_STATUS_FAILED;
7178 eir_len = 0;
7179 } else {
7180 status = MGMT_STATUS_SUCCESS;
7181 rp = (void *)skb->data;
7182
7183 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
7184 eir_len = 5 + 18 + 18;
7185 h192 = NULL;
7186 r192 = NULL;
7187 } else {
7188 eir_len = 5 + 18 + 18 + 18 + 18;
7189 h192 = rp->hash192;
7190 r192 = rp->rand192;
7191 }
7192
7193 h256 = rp->hash256;
7194 r256 = rp->rand256;
7195 }
7196 }
7197
7198 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
7199 if (!mgmt_rp)
7200 goto done;
7201
7202 if (status)
7203 goto send_rsp;
7204
7205 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
7206 hdev->dev_class, 3);
7207
7208 if (h192 && r192) {
7209 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7210 EIR_SSP_HASH_C192, h192, 16);
7211 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7212 EIR_SSP_RAND_R192, r192, 16);
7213 }
7214
7215 if (h256 && r256) {
7216 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7217 EIR_SSP_HASH_C256, h256, 16);
7218 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
7219 EIR_SSP_RAND_R256, r256, 16);
7220 }
7221
7222send_rsp:
7223 mgmt_rp->type = mgmt_cp->type;
7224 mgmt_rp->eir_len = cpu_to_le16(eir_len);
7225
7226 err = mgmt_cmd_complete(cmd->sk, hdev->id,
7227 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
7228 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
7229 if (err < 0 || status)
7230 goto done;
7231
7232 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
7233
7234 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7235 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
7236 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
7237done:
7238 kfree(mgmt_rp);
7239 mgmt_pending_remove(cmd);
7240}
7241
7242static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
7243 struct mgmt_cp_read_local_oob_ext_data *cp)
7244{
7245 struct mgmt_pending_cmd *cmd;
7246 struct hci_request req;
7247 int err;
7248
7249 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
7250 cp, sizeof(*cp));
7251 if (!cmd)
7252 return -ENOMEM;
7253
7254 hci_req_init(&req, hdev);
7255
7256 if (bredr_sc_enabled(hdev))
7257 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
7258 else
7259 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
7260
7261 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
7262 if (err < 0) {
7263 mgmt_pending_remove(cmd);
7264 return err;
7265 }
7266
7267 return 0;
7268}
7269
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007270static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
7271 void *data, u16 data_len)
7272{
7273 struct mgmt_cp_read_local_oob_ext_data *cp = data;
7274 struct mgmt_rp_read_local_oob_ext_data *rp;
7275 size_t rp_len;
7276 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007277 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007278 int err;
7279
Marcel Holtmann181d6952020-05-06 09:57:47 +02007280 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007281
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007282 if (hdev_is_powered(hdev)) {
7283 switch (cp->type) {
7284 case BIT(BDADDR_BREDR):
7285 status = mgmt_bredr_support(hdev);
7286 if (status)
7287 eir_len = 0;
7288 else
7289 eir_len = 5;
7290 break;
7291 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
7292 status = mgmt_le_support(hdev);
7293 if (status)
7294 eir_len = 0;
7295 else
7296 eir_len = 9 + 3 + 18 + 18 + 3;
7297 break;
7298 default:
7299 status = MGMT_STATUS_INVALID_PARAMS;
7300 eir_len = 0;
7301 break;
7302 }
7303 } else {
7304 status = MGMT_STATUS_NOT_POWERED;
7305 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007306 }
7307
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007308 rp_len = sizeof(*rp) + eir_len;
7309 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007310 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007311 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007312
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007313 if (status)
7314 goto complete;
7315
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007316 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007317
7318 eir_len = 0;
7319 switch (cp->type) {
7320 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03007321 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7322 err = read_local_ssp_oob_req(hdev, sk, cp);
7323 hci_dev_unlock(hdev);
7324 if (!err)
7325 goto done;
7326
7327 status = MGMT_STATUS_FAILED;
7328 goto complete;
7329 } else {
7330 eir_len = eir_append_data(rp->eir, eir_len,
7331 EIR_CLASS_OF_DEV,
7332 hdev->dev_class, 3);
7333 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007334 break;
7335 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07007336 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
7337 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007338 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007339 status = MGMT_STATUS_FAILED;
7340 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007341 }
7342
Marcel Holtmanne2135682015-04-02 12:00:58 -07007343 /* This should return the active RPA, but since the RPA
7344 * is only programmed on demand, it is really hard to fill
7345 * this in at the moment. For now disallow retrieving
7346 * local out-of-band data when privacy is in use.
7347 *
7348 * Returning the identity address will not help here since
7349 * pairing happens before the identity resolving key is
7350 * known and thus the connection establishment happens
7351 * based on the RPA and not the identity address.
7352 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007353 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07007354 hci_dev_unlock(hdev);
7355 status = MGMT_STATUS_REJECTED;
7356 goto complete;
7357 }
7358
7359 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7360 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7361 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7362 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007363 memcpy(addr, &hdev->static_addr, 6);
7364 addr[6] = 0x01;
7365 } else {
7366 memcpy(addr, &hdev->bdaddr, 6);
7367 addr[6] = 0x00;
7368 }
7369
7370 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7371 addr, sizeof(addr));
7372
7373 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7374 role = 0x02;
7375 else
7376 role = 0x01;
7377
7378 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7379 &role, sizeof(role));
7380
Marcel Holtmann5082a592015-03-16 12:39:00 -07007381 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7382 eir_len = eir_append_data(rp->eir, eir_len,
7383 EIR_LE_SC_CONFIRM,
7384 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007385
Marcel Holtmann5082a592015-03-16 12:39:00 -07007386 eir_len = eir_append_data(rp->eir, eir_len,
7387 EIR_LE_SC_RANDOM,
7388 rand, sizeof(rand));
7389 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007390
Johan Hedbergf2252572015-11-18 12:49:20 +02007391 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007392
7393 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7394 flags |= LE_AD_NO_BREDR;
7395
7396 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7397 &flags, sizeof(flags));
7398 break;
7399 }
7400
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007401 hci_dev_unlock(hdev);
7402
Marcel Holtmann72000df2015-03-16 16:11:21 -07007403 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7404
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007405 status = MGMT_STATUS_SUCCESS;
7406
7407complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007408 rp->type = cp->type;
7409 rp->eir_len = cpu_to_le16(eir_len);
7410
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007411 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007412 status, rp, sizeof(*rp) + eir_len);
7413 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007414 goto done;
7415
7416 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7417 rp, sizeof(*rp) + eir_len,
7418 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007419
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007420done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007421 kfree(rp);
7422
7423 return err;
7424}
7425
Arman Uguray089fa8c2015-03-25 18:53:45 -07007426static u32 get_supported_adv_flags(struct hci_dev *hdev)
7427{
7428 u32 flags = 0;
7429
7430 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7431 flags |= MGMT_ADV_FLAG_DISCOV;
7432 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7433 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007434 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007435 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Daniel Winkler12410572020-12-03 12:12:49 -08007436 flags |= MGMT_ADV_PARAM_DURATION;
7437 flags |= MGMT_ADV_PARAM_TIMEOUT;
7438 flags |= MGMT_ADV_PARAM_INTERVALS;
7439 flags |= MGMT_ADV_PARAM_TX_POWER;
Daniel Winklerff02db12021-03-03 11:15:23 -08007440 flags |= MGMT_ADV_PARAM_SCAN_RSP;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007441
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307442 /* In extended adv TX_POWER returned from Set Adv Param
7443 * will be always valid.
7444 */
7445 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7446 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007447 flags |= MGMT_ADV_FLAG_TX_POWER;
7448
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307449 if (ext_adv_capable(hdev)) {
7450 flags |= MGMT_ADV_FLAG_SEC_1M;
Daniel Winklerd5ea32d2020-08-25 16:31:51 -07007451 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
7452 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307453
7454 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7455 flags |= MGMT_ADV_FLAG_SEC_2M;
7456
7457 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7458 flags |= MGMT_ADV_FLAG_SEC_CODED;
7459 }
7460
Arman Uguray089fa8c2015-03-25 18:53:45 -07007461 return flags;
7462}
7463
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007464static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7465 void *data, u16 data_len)
7466{
7467 struct mgmt_rp_read_adv_features *rp;
7468 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007469 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007470 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007471 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007472 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007473
Marcel Holtmann181d6952020-05-06 09:57:47 +02007474 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007475
Arman Uguray089fa8c2015-03-25 18:53:45 -07007476 if (!lmp_le_capable(hdev))
7477 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7478 MGMT_STATUS_REJECTED);
7479
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307480 /* Enabling the experimental LL Privay support disables support for
7481 * advertising.
7482 */
7483 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
Marcel Holtmann21dd1182021-03-14 14:56:08 +01007484 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307485 MGMT_STATUS_NOT_SUPPORTED);
7486
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007487 hci_dev_lock(hdev);
7488
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007489 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007490 rp = kmalloc(rp_len, GFP_ATOMIC);
7491 if (!rp) {
7492 hci_dev_unlock(hdev);
7493 return -ENOMEM;
7494 }
7495
Arman Uguray089fa8c2015-03-25 18:53:45 -07007496 supported_flags = get_supported_adv_flags(hdev);
7497
7498 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007499 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7500 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Daniel Winkler87597482020-08-25 16:31:50 -07007501 rp->max_instances = hdev->le_num_of_adv_sets;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007502 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007503
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007504 instance = rp->instance;
7505 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7506 *instance = adv_instance->instance;
7507 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007508 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007509
7510 hci_dev_unlock(hdev);
7511
7512 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7513 MGMT_STATUS_SUCCESS, rp, rp_len);
7514
7515 kfree(rp);
7516
7517 return err;
7518}
7519
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007520static u8 calculate_name_len(struct hci_dev *hdev)
7521{
7522 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7523
7524 return append_local_name(hdev, buf, 0);
7525}
7526
7527static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7528 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007529{
Arman Uguray4117ed72015-03-23 15:57:14 -07007530 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007531
Marcel Holtmann31a32482015-11-19 16:16:42 +01007532 if (is_adv_data) {
7533 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7534 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007535 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007536 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007537
Szymon Janc2bb368702016-09-18 12:50:05 +02007538 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007539 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007540 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007541 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007542 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007543
Szymon Janc2bb368702016-09-18 12:50:05 +02007544 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007545 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007546 }
7547
Szymon Janc2bb368702016-09-18 12:50:05 +02007548 return max_len;
7549}
7550
7551static bool flags_managed(u32 adv_flags)
7552{
7553 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7554 MGMT_ADV_FLAG_LIMITED_DISCOV |
7555 MGMT_ADV_FLAG_MANAGED_FLAGS);
7556}
7557
7558static bool tx_power_managed(u32 adv_flags)
7559{
7560 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7561}
7562
7563static bool name_managed(u32 adv_flags)
7564{
7565 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7566}
7567
7568static bool appearance_managed(u32 adv_flags)
7569{
7570 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7571}
7572
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007573static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7574 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007575{
7576 int i, cur_len;
7577 u8 max_len;
7578
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007579 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007580
Arman Uguray4117ed72015-03-23 15:57:14 -07007581 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007582 return false;
7583
Arman Uguray4117ed72015-03-23 15:57:14 -07007584 /* Make sure that the data is correctly formatted. */
7585 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7586 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007587
Szymon Janc9c9db782016-09-18 12:50:06 +02007588 if (data[i + 1] == EIR_FLAGS &&
7589 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007590 return false;
7591
Szymon Janc2bb368702016-09-18 12:50:05 +02007592 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7593 return false;
7594
7595 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7596 return false;
7597
7598 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7599 return false;
7600
7601 if (data[i + 1] == EIR_APPEARANCE &&
7602 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007603 return false;
7604
Arman Uguray24b4f382015-03-23 15:57:12 -07007605 /* If the current field length would exceed the total data
7606 * length, then it's invalid.
7607 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007608 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007609 return false;
7610 }
7611
7612 return true;
7613}
7614
Daniel Winkler12410572020-12-03 12:12:49 -08007615static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
7616{
7617 u32 supported_flags, phy_flags;
7618
7619 /* The current implementation only supports a subset of the specified
7620 * flags. Also need to check mutual exclusiveness of sec flags.
7621 */
7622 supported_flags = get_supported_adv_flags(hdev);
7623 phy_flags = adv_flags & MGMT_ADV_FLAG_SEC_MASK;
7624 if (adv_flags & ~supported_flags ||
7625 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
7626 return false;
7627
7628 return true;
7629}
7630
7631static bool adv_busy(struct hci_dev *hdev)
7632{
7633 return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7634 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7635 pending_find(MGMT_OP_SET_LE, hdev) ||
7636 pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
7637 pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
7638}
7639
Arman Uguray24b4f382015-03-23 15:57:12 -07007640static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7641 u16 opcode)
7642{
7643 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007644 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007645 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007646 struct adv_info *adv_instance, *n;
7647 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007648
Marcel Holtmann181d6952020-05-06 09:57:47 +02007649 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007650
7651 hci_dev_lock(hdev);
7652
7653 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
Daniel Winkler12410572020-12-03 12:12:49 -08007654 if (!cmd)
7655 cmd = pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev);
Arman Uguray24b4f382015-03-23 15:57:12 -07007656
Florian Grandelfffd38b2015-06-18 03:16:47 +02007657 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7658 if (!adv_instance->pending)
7659 continue;
7660
7661 if (!status) {
7662 adv_instance->pending = false;
7663 continue;
7664 }
7665
7666 instance = adv_instance->instance;
7667
7668 if (hdev->cur_adv_instance == instance)
7669 cancel_adv_timeout(hdev);
7670
7671 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007672 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007673 }
7674
7675 if (!cmd)
7676 goto unlock;
7677
Florian Grandelfffd38b2015-06-18 03:16:47 +02007678 cp = cmd->param;
7679 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007680
7681 if (status)
7682 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7683 mgmt_status(status));
7684 else
7685 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7686 mgmt_status(status), &rp, sizeof(rp));
7687
7688 mgmt_pending_remove(cmd);
7689
7690unlock:
7691 hci_dev_unlock(hdev);
7692}
7693
7694static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7695 void *data, u16 data_len)
7696{
7697 struct mgmt_cp_add_advertising *cp = data;
7698 struct mgmt_rp_add_advertising rp;
7699 u32 flags;
7700 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007701 u16 timeout, duration;
7702 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7703 u8 schedule_instance = 0;
7704 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007705 int err;
7706 struct mgmt_pending_cmd *cmd;
7707 struct hci_request req;
7708
Marcel Holtmann181d6952020-05-06 09:57:47 +02007709 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007710
7711 status = mgmt_le_support(hdev);
7712 if (status)
7713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7714 status);
7715
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05307716 /* Enabling the experimental LL Privay support disables support for
7717 * advertising.
7718 */
7719 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
7720 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
7721 MGMT_STATUS_NOT_SUPPORTED);
7722
Daniel Winkler87597482020-08-25 16:31:50 -07007723 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007724 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7725 MGMT_STATUS_INVALID_PARAMS);
7726
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007727 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7728 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7729 MGMT_STATUS_INVALID_PARAMS);
7730
Arman Uguray24b4f382015-03-23 15:57:12 -07007731 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007732 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007733 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007734
Daniel Winkler12410572020-12-03 12:12:49 -08007735 if (!requested_adv_flags_are_valid(hdev, flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07007736 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7737 MGMT_STATUS_INVALID_PARAMS);
7738
7739 hci_dev_lock(hdev);
7740
Arman Uguray912098a2015-03-23 15:57:15 -07007741 if (timeout && !hdev_is_powered(hdev)) {
7742 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7743 MGMT_STATUS_REJECTED);
7744 goto unlock;
7745 }
7746
Daniel Winkler12410572020-12-03 12:12:49 -08007747 if (adv_busy(hdev)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007748 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7749 MGMT_STATUS_BUSY);
7750 goto unlock;
7751 }
7752
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007753 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7754 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007755 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007756 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7757 MGMT_STATUS_INVALID_PARAMS);
7758 goto unlock;
7759 }
7760
Florian Grandelfffd38b2015-06-18 03:16:47 +02007761 err = hci_add_adv_instance(hdev, cp->instance, flags,
7762 cp->adv_data_len, cp->data,
7763 cp->scan_rsp_len,
7764 cp->data + cp->adv_data_len,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08007765 timeout, duration,
7766 HCI_ADV_TX_POWER_NO_PREFERENCE,
7767 hdev->le_adv_min_interval,
7768 hdev->le_adv_max_interval);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007769 if (err < 0) {
7770 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7771 MGMT_STATUS_FAILED);
7772 goto unlock;
7773 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007774
Florian Grandelfffd38b2015-06-18 03:16:47 +02007775 /* Only trigger an advertising added event if a new instance was
7776 * actually added.
7777 */
7778 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007779 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007780
Florian Grandelfffd38b2015-06-18 03:16:47 +02007781 if (hdev->cur_adv_instance == cp->instance) {
7782 /* If the currently advertised instance is being changed then
7783 * cancel the current advertising and schedule the next
7784 * instance. If there is only one instance then the overridden
7785 * advertising data will be visible right away.
7786 */
7787 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007788
Florian Grandelfffd38b2015-06-18 03:16:47 +02007789 next_instance = hci_get_next_instance(hdev, cp->instance);
7790 if (next_instance)
7791 schedule_instance = next_instance->instance;
7792 } else if (!hdev->adv_instance_timeout) {
7793 /* Immediately advertise the new instance if no other
7794 * instance is currently being advertised.
7795 */
7796 schedule_instance = cp->instance;
7797 }
Arman Uguray912098a2015-03-23 15:57:15 -07007798
Florian Grandelfffd38b2015-06-18 03:16:47 +02007799 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7800 * there is no instance to be advertised then we have no HCI
7801 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007802 */
7803 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007804 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7805 !schedule_instance) {
7806 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007807 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7808 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7809 goto unlock;
7810 }
7811
7812 /* We're good to go, update advertising data, parameters, and start
7813 * advertising.
7814 */
7815 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7816 data_len);
7817 if (!cmd) {
7818 err = -ENOMEM;
7819 goto unlock;
7820 }
7821
7822 hci_req_init(&req, hdev);
7823
Johan Hedbergf2252572015-11-18 12:49:20 +02007824 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007825
Florian Grandelfffd38b2015-06-18 03:16:47 +02007826 if (!err)
7827 err = hci_req_run(&req, add_advertising_complete);
7828
Joseph Hwang72da7b22020-03-10 09:31:50 -07007829 if (err < 0) {
7830 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7831 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007832 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007833 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007834
7835unlock:
7836 hci_dev_unlock(hdev);
7837
7838 return err;
7839}
7840
Daniel Winkler12410572020-12-03 12:12:49 -08007841static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status,
7842 u16 opcode)
7843{
7844 struct mgmt_pending_cmd *cmd;
7845 struct mgmt_cp_add_ext_adv_params *cp;
7846 struct mgmt_rp_add_ext_adv_params rp;
7847 struct adv_info *adv_instance;
7848 u32 flags;
7849
7850 BT_DBG("%s", hdev->name);
7851
7852 hci_dev_lock(hdev);
7853
7854 cmd = pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev);
7855 if (!cmd)
7856 goto unlock;
7857
7858 cp = cmd->param;
7859 adv_instance = hci_find_adv_instance(hdev, cp->instance);
7860 if (!adv_instance)
7861 goto unlock;
7862
7863 rp.instance = cp->instance;
7864 rp.tx_power = adv_instance->tx_power;
7865
7866 /* While we're at it, inform userspace of the available space for this
7867 * advertisement, given the flags that will be used.
7868 */
7869 flags = __le32_to_cpu(cp->flags);
7870 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7871 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
7872
7873 if (status) {
7874 /* If this advertisement was previously advertising and we
7875 * failed to update it, we signal that it has been removed and
7876 * delete its structure
7877 */
7878 if (!adv_instance->pending)
7879 mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
7880
7881 hci_remove_adv_instance(hdev, cp->instance);
7882
7883 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7884 mgmt_status(status));
7885
7886 } else {
7887 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7888 mgmt_status(status), &rp, sizeof(rp));
7889 }
7890
7891unlock:
7892 if (cmd)
7893 mgmt_pending_remove(cmd);
7894
7895 hci_dev_unlock(hdev);
7896}
7897
7898static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
7899 void *data, u16 data_len)
7900{
7901 struct mgmt_cp_add_ext_adv_params *cp = data;
7902 struct mgmt_rp_add_ext_adv_params rp;
7903 struct mgmt_pending_cmd *cmd = NULL;
7904 struct adv_info *adv_instance;
7905 struct hci_request req;
7906 u32 flags, min_interval, max_interval;
7907 u16 timeout, duration;
7908 u8 status;
7909 s8 tx_power;
7910 int err;
7911
7912 BT_DBG("%s", hdev->name);
7913
7914 status = mgmt_le_support(hdev);
7915 if (status)
7916 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7917 status);
7918
7919 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
7920 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7921 MGMT_STATUS_INVALID_PARAMS);
7922
7923 /* The purpose of breaking add_advertising into two separate MGMT calls
7924 * for params and data is to allow more parameters to be added to this
7925 * structure in the future. For this reason, we verify that we have the
7926 * bare minimum structure we know of when the interface was defined. Any
7927 * extra parameters we don't know about will be ignored in this request.
7928 */
7929 if (data_len < MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE)
7930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7931 MGMT_STATUS_INVALID_PARAMS);
7932
7933 flags = __le32_to_cpu(cp->flags);
7934
7935 if (!requested_adv_flags_are_valid(hdev, flags))
7936 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7937 MGMT_STATUS_INVALID_PARAMS);
7938
7939 hci_dev_lock(hdev);
7940
7941 /* In new interface, we require that we are powered to register */
7942 if (!hdev_is_powered(hdev)) {
7943 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7944 MGMT_STATUS_REJECTED);
7945 goto unlock;
7946 }
7947
7948 if (adv_busy(hdev)) {
7949 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7950 MGMT_STATUS_BUSY);
7951 goto unlock;
7952 }
7953
7954 /* Parse defined parameters from request, use defaults otherwise */
7955 timeout = (flags & MGMT_ADV_PARAM_TIMEOUT) ?
7956 __le16_to_cpu(cp->timeout) : 0;
7957
7958 duration = (flags & MGMT_ADV_PARAM_DURATION) ?
7959 __le16_to_cpu(cp->duration) :
7960 hdev->def_multi_adv_rotation_duration;
7961
7962 min_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
7963 __le32_to_cpu(cp->min_interval) :
7964 hdev->le_adv_min_interval;
7965
7966 max_interval = (flags & MGMT_ADV_PARAM_INTERVALS) ?
7967 __le32_to_cpu(cp->max_interval) :
7968 hdev->le_adv_max_interval;
7969
7970 tx_power = (flags & MGMT_ADV_PARAM_TX_POWER) ?
7971 cp->tx_power :
7972 HCI_ADV_TX_POWER_NO_PREFERENCE;
7973
7974 /* Create advertising instance with no advertising or response data */
7975 err = hci_add_adv_instance(hdev, cp->instance, flags,
Daniel Winkler9bf9f4b2020-12-03 12:12:50 -08007976 0, NULL, 0, NULL, timeout, duration,
7977 tx_power, min_interval, max_interval);
Daniel Winkler12410572020-12-03 12:12:49 -08007978
7979 if (err < 0) {
7980 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS,
7981 MGMT_STATUS_FAILED);
7982 goto unlock;
7983 }
7984
Daniel Winkler12410572020-12-03 12:12:49 -08007985 /* Submit request for advertising params if ext adv available */
7986 if (ext_adv_capable(hdev)) {
7987 hci_req_init(&req, hdev);
7988 adv_instance = hci_find_adv_instance(hdev, cp->instance);
7989
7990 /* Updating parameters of an active instance will return a
7991 * Command Disallowed error, so we must first disable the
7992 * instance if it is active.
7993 */
7994 if (!adv_instance->pending)
7995 __hci_req_disable_ext_adv_instance(&req, cp->instance);
7996
7997 __hci_req_setup_ext_adv_instance(&req, cp->instance);
7998
7999 err = hci_req_run(&req, add_ext_adv_params_complete);
8000
8001 if (!err)
8002 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_PARAMS,
8003 hdev, data, data_len);
8004 if (!cmd) {
8005 err = -ENOMEM;
8006 hci_remove_adv_instance(hdev, cp->instance);
8007 goto unlock;
8008 }
8009
8010 } else {
8011 rp.instance = cp->instance;
8012 rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
8013 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8014 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
8015 err = mgmt_cmd_complete(sk, hdev->id,
8016 MGMT_OP_ADD_EXT_ADV_PARAMS,
8017 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8018 }
8019
8020unlock:
8021 hci_dev_unlock(hdev);
8022
8023 return err;
8024}
8025
8026static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
8027 u16 data_len)
8028{
8029 struct mgmt_cp_add_ext_adv_data *cp = data;
8030 struct mgmt_rp_add_ext_adv_data rp;
8031 u8 schedule_instance = 0;
8032 struct adv_info *next_instance;
8033 struct adv_info *adv_instance;
8034 int err = 0;
8035 struct mgmt_pending_cmd *cmd;
8036 struct hci_request req;
8037
8038 BT_DBG("%s", hdev->name);
8039
8040 hci_dev_lock(hdev);
8041
8042 adv_instance = hci_find_adv_instance(hdev, cp->instance);
8043
8044 if (!adv_instance) {
8045 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8046 MGMT_STATUS_INVALID_PARAMS);
8047 goto unlock;
8048 }
8049
8050 /* In new interface, we require that we are powered to register */
8051 if (!hdev_is_powered(hdev)) {
8052 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8053 MGMT_STATUS_REJECTED);
8054 goto clear_new_instance;
8055 }
8056
8057 if (adv_busy(hdev)) {
8058 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8059 MGMT_STATUS_BUSY);
8060 goto clear_new_instance;
8061 }
8062
8063 /* Validate new data */
8064 if (!tlv_data_is_valid(hdev, adv_instance->flags, cp->data,
8065 cp->adv_data_len, true) ||
8066 !tlv_data_is_valid(hdev, adv_instance->flags, cp->data +
8067 cp->adv_data_len, cp->scan_rsp_len, false)) {
8068 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8069 MGMT_STATUS_INVALID_PARAMS);
8070 goto clear_new_instance;
8071 }
8072
8073 /* Set the data in the advertising instance */
8074 hci_set_adv_instance_data(hdev, cp->instance, cp->adv_data_len,
8075 cp->data, cp->scan_rsp_len,
8076 cp->data + cp->adv_data_len);
8077
8078 /* We're good to go, update advertising data, parameters, and start
8079 * advertising.
8080 */
8081
8082 hci_req_init(&req, hdev);
8083
8084 hci_req_add(&req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
8085
8086 if (ext_adv_capable(hdev)) {
8087 __hci_req_update_adv_data(&req, cp->instance);
8088 __hci_req_update_scan_rsp_data(&req, cp->instance);
8089 __hci_req_enable_ext_advertising(&req, cp->instance);
8090
8091 } else {
8092 /* If using software rotation, determine next instance to use */
8093
8094 if (hdev->cur_adv_instance == cp->instance) {
8095 /* If the currently advertised instance is being changed
8096 * then cancel the current advertising and schedule the
8097 * next instance. If there is only one instance then the
8098 * overridden advertising data will be visible right
8099 * away
8100 */
8101 cancel_adv_timeout(hdev);
8102
8103 next_instance = hci_get_next_instance(hdev,
8104 cp->instance);
8105 if (next_instance)
8106 schedule_instance = next_instance->instance;
8107 } else if (!hdev->adv_instance_timeout) {
8108 /* Immediately advertise the new instance if no other
8109 * instance is currently being advertised.
8110 */
8111 schedule_instance = cp->instance;
8112 }
8113
8114 /* If the HCI_ADVERTISING flag is set or there is no instance to
8115 * be advertised then we have no HCI communication to make.
8116 * Simply return.
8117 */
8118 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
8119 !schedule_instance) {
8120 if (adv_instance->pending) {
8121 mgmt_advertising_added(sk, hdev, cp->instance);
8122 adv_instance->pending = false;
8123 }
8124 rp.instance = cp->instance;
8125 err = mgmt_cmd_complete(sk, hdev->id,
8126 MGMT_OP_ADD_EXT_ADV_DATA,
8127 MGMT_STATUS_SUCCESS, &rp,
8128 sizeof(rp));
8129 goto unlock;
8130 }
8131
8132 err = __hci_req_schedule_adv_instance(&req, schedule_instance,
8133 true);
8134 }
8135
8136 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
8137 data_len);
8138 if (!cmd) {
8139 err = -ENOMEM;
8140 goto clear_new_instance;
8141 }
8142
8143 if (!err)
8144 err = hci_req_run(&req, add_advertising_complete);
8145
8146 if (err < 0) {
8147 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
8148 MGMT_STATUS_FAILED);
8149 mgmt_pending_remove(cmd);
8150 goto clear_new_instance;
8151 }
8152
8153 /* We were successful in updating data, so trigger advertising_added
8154 * event if this is an instance that wasn't previously advertising. If
8155 * a failure occurs in the requests we initiated, we will remove the
8156 * instance again in add_advertising_complete
8157 */
8158 if (adv_instance->pending)
8159 mgmt_advertising_added(sk, hdev, cp->instance);
8160
8161 goto unlock;
8162
8163clear_new_instance:
8164 hci_remove_adv_instance(hdev, cp->instance);
8165
8166unlock:
8167 hci_dev_unlock(hdev);
8168
8169 return err;
8170}
8171
Arman Ugurayda9293352015-03-23 15:57:13 -07008172static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
8173 u16 opcode)
8174{
8175 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02008176 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07008177 struct mgmt_rp_remove_advertising rp;
8178
Marcel Holtmann181d6952020-05-06 09:57:47 +02008179 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07008180
8181 hci_dev_lock(hdev);
8182
8183 /* A failure status here only means that we failed to disable
8184 * advertising. Otherwise, the advertising instance has been removed,
8185 * so report success.
8186 */
8187 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
8188 if (!cmd)
8189 goto unlock;
8190
Florian Grandel01948332015-06-18 03:16:48 +02008191 cp = cmd->param;
8192 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008193
8194 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
8195 &rp, sizeof(rp));
8196 mgmt_pending_remove(cmd);
8197
8198unlock:
8199 hci_dev_unlock(hdev);
8200}
8201
8202static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
8203 void *data, u16 data_len)
8204{
8205 struct mgmt_cp_remove_advertising *cp = data;
8206 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07008207 struct mgmt_pending_cmd *cmd;
8208 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03008209 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07008210
Marcel Holtmann181d6952020-05-06 09:57:47 +02008211 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07008212
Sathish Narasimmancbbdfa62020-07-23 18:09:03 +05308213 /* Enabling the experimental LL Privay support disables support for
8214 * advertising.
8215 */
8216 if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
8217 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
8218 MGMT_STATUS_NOT_SUPPORTED);
8219
Arman Ugurayda9293352015-03-23 15:57:13 -07008220 hci_dev_lock(hdev);
8221
Johan Hedberg952497b2015-06-18 21:05:31 +03008222 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02008223 err = mgmt_cmd_status(sk, hdev->id,
8224 MGMT_OP_REMOVE_ADVERTISING,
8225 MGMT_STATUS_INVALID_PARAMS);
8226 goto unlock;
8227 }
8228
Arman Ugurayda9293352015-03-23 15:57:13 -07008229 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
8230 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
8231 pending_find(MGMT_OP_SET_LE, hdev)) {
8232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8233 MGMT_STATUS_BUSY);
8234 goto unlock;
8235 }
8236
Johan Hedberg17fd08f2015-11-26 12:15:59 +02008237 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07008238 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
8239 MGMT_STATUS_INVALID_PARAMS);
8240 goto unlock;
8241 }
8242
Florian Grandel01948332015-06-18 03:16:48 +02008243 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07008244
Daniel Winkler37adf702020-07-14 14:16:00 -07008245 /* If we use extended advertising, instance is disabled and removed */
8246 if (ext_adv_capable(hdev)) {
8247 __hci_req_disable_ext_adv_instance(&req, cp->instance);
8248 __hci_req_remove_ext_adv_instance(&req, cp->instance);
8249 }
8250
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03008251 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07008252
Florian Grandel01948332015-06-18 03:16:48 +02008253 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02008254 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07008255
Florian Grandel01948332015-06-18 03:16:48 +02008256 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
8257 * flag is set or the device isn't powered then we have no HCI
8258 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07008259 */
Florian Grandel01948332015-06-18 03:16:48 +02008260 if (skb_queue_empty(&req.cmd_q) ||
8261 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07008262 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05308263 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02008264 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07008265 err = mgmt_cmd_complete(sk, hdev->id,
8266 MGMT_OP_REMOVE_ADVERTISING,
8267 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8268 goto unlock;
8269 }
8270
8271 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
8272 data_len);
8273 if (!cmd) {
8274 err = -ENOMEM;
8275 goto unlock;
8276 }
8277
Arman Ugurayda9293352015-03-23 15:57:13 -07008278 err = hci_req_run(&req, remove_advertising_complete);
8279 if (err < 0)
8280 mgmt_pending_remove(cmd);
8281
8282unlock:
8283 hci_dev_unlock(hdev);
8284
8285 return err;
8286}
8287
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008288static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
8289 void *data, u16 data_len)
8290{
8291 struct mgmt_cp_get_adv_size_info *cp = data;
8292 struct mgmt_rp_get_adv_size_info rp;
8293 u32 flags, supported_flags;
8294 int err;
8295
Marcel Holtmann181d6952020-05-06 09:57:47 +02008296 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008297
8298 if (!lmp_le_capable(hdev))
8299 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8300 MGMT_STATUS_REJECTED);
8301
Daniel Winkler87597482020-08-25 16:31:50 -07008302 if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008303 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8304 MGMT_STATUS_INVALID_PARAMS);
8305
8306 flags = __le32_to_cpu(cp->flags);
8307
8308 /* The current implementation only supports a subset of the specified
8309 * flags.
8310 */
8311 supported_flags = get_supported_adv_flags(hdev);
8312 if (flags & ~supported_flags)
8313 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8314 MGMT_STATUS_INVALID_PARAMS);
8315
8316 rp.instance = cp->instance;
8317 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02008318 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
8319 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008320
8321 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
8322 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
8323
8324 return err;
8325}
8326
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008327static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008328 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008329 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008330 HCI_MGMT_NO_HDEV |
8331 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008332 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008333 HCI_MGMT_NO_HDEV |
8334 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008335 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008336 HCI_MGMT_NO_HDEV |
8337 HCI_MGMT_UNTRUSTED },
8338 { read_controller_info, MGMT_READ_INFO_SIZE,
8339 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008340 { set_powered, MGMT_SETTING_SIZE },
8341 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
8342 { set_connectable, MGMT_SETTING_SIZE },
8343 { set_fast_connectable, MGMT_SETTING_SIZE },
8344 { set_bondable, MGMT_SETTING_SIZE },
8345 { set_link_security, MGMT_SETTING_SIZE },
8346 { set_ssp, MGMT_SETTING_SIZE },
8347 { set_hs, MGMT_SETTING_SIZE },
8348 { set_le, MGMT_SETTING_SIZE },
8349 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
8350 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
8351 { add_uuid, MGMT_ADD_UUID_SIZE },
8352 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008353 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
8354 HCI_MGMT_VAR_LEN },
8355 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
8356 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008357 { disconnect, MGMT_DISCONNECT_SIZE },
8358 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
8359 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
8360 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
8361 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
8362 { pair_device, MGMT_PAIR_DEVICE_SIZE },
8363 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
8364 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
8365 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
8366 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
8367 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
8368 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008369 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
8370 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
8371 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008372 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
8373 { start_discovery, MGMT_START_DISCOVERY_SIZE },
8374 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
8375 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
8376 { block_device, MGMT_BLOCK_DEVICE_SIZE },
8377 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
8378 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
8379 { set_advertising, MGMT_SETTING_SIZE },
8380 { set_bredr, MGMT_SETTING_SIZE },
8381 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
8382 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
8383 { set_secure_conn, MGMT_SETTING_SIZE },
8384 { set_debug_keys, MGMT_SETTING_SIZE },
8385 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008386 { load_irks, MGMT_LOAD_IRKS_SIZE,
8387 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07008388 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
8389 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
8390 { add_device, MGMT_ADD_DEVICE_SIZE },
8391 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008392 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
8393 HCI_MGMT_VAR_LEN },
8394 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008395 HCI_MGMT_NO_HDEV |
8396 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008397 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008398 HCI_MGMT_UNCONFIGURED |
8399 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02008400 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
8401 HCI_MGMT_UNCONFIGURED },
8402 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
8403 HCI_MGMT_UNCONFIGURED },
8404 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
8405 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07008406 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07008407 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07008408 HCI_MGMT_NO_HDEV |
8409 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07008410 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07008411 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
8412 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07008413 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01008414 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02008415 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008416 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
8417 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02008418 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05308419 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05308420 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00008421 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
8422 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00008423 { set_wideband_speech, MGMT_SETTING_SIZE },
Daniel Winkler4d9b9522020-12-03 12:12:52 -08008424 { read_controller_cap, MGMT_READ_CONTROLLER_CAP_SIZE,
Marcel Holtmannbc292252020-04-03 21:44:05 +02008425 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02008426 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
8427 HCI_MGMT_UNTRUSTED |
8428 HCI_MGMT_HDEV_OPTIONAL },
8429 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
8430 HCI_MGMT_VAR_LEN |
8431 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00008432 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
8433 HCI_MGMT_UNTRUSTED },
8434 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
8435 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02008436 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
8437 HCI_MGMT_UNTRUSTED },
8438 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
8439 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02008440 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
8441 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02008442 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02008443 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
8444 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02008445 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Daniel Winkler12410572020-12-03 12:12:49 -08008446 { add_ext_adv_params, MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE,
8447 HCI_MGMT_VAR_LEN },
8448 { add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
8449 HCI_MGMT_VAR_LEN },
Archie Pusakab4a221e2021-01-22 16:36:11 +08008450 { add_adv_patterns_monitor_rssi,
8451 MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
8452 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02008453};
8454
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008455void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008456{
Marcel Holtmannced85542015-03-14 19:27:56 -07008457 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03008458
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008459 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8460 return;
8461
Marcel Holtmannf9207332015-03-14 19:27:55 -07008462 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008463 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008464 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8465 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
8466 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008467 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008468 } else {
8469 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
8470 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008471 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008472 }
8473 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008474 case HCI_AMP:
8475 ev.type = 0x02;
8476 break;
8477 default:
8478 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008479 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008480
8481 ev.bus = hdev->bus;
8482
8483 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
8484 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008485}
8486
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07008487void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02008488{
Marcel Holtmannced85542015-03-14 19:27:56 -07008489 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02008490 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02008491
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02008492 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
8493 return;
8494
Marcel Holtmannf9207332015-03-14 19:27:55 -07008495 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02008496 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07008497 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02008498
Marcel Holtmannf9207332015-03-14 19:27:55 -07008499 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
8500 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
8501 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008502 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008503 } else {
8504 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
8505 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07008506 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008507 }
8508 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07008509 case HCI_AMP:
8510 ev.type = 0x02;
8511 break;
8512 default:
8513 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07008514 }
Marcel Holtmannced85542015-03-14 19:27:56 -07008515
8516 ev.bus = hdev->bus;
8517
8518 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
8519 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008520}
8521
Andre Guedes6046dc32014-02-26 20:21:51 -03008522/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008523static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03008524{
8525 struct hci_conn_params *p;
8526
8527 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03008528 /* Needed for AUTO_OFF case where might not "really"
8529 * have been powered off.
8530 */
8531 list_del_init(&p->action);
8532
8533 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02008534 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03008535 case HCI_AUTO_CONN_ALWAYS:
8536 list_add(&p->action, &hdev->pend_le_conns);
8537 break;
8538 case HCI_AUTO_CONN_REPORT:
8539 list_add(&p->action, &hdev->pend_le_reports);
8540 break;
8541 default:
8542 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02008543 }
Andre Guedes6046dc32014-02-26 20:21:51 -03008544 }
8545}
8546
Johan Hedberg2ff13892015-11-25 16:15:44 +02008547void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05008548{
8549 struct cmd_lookup match = { NULL, hdev };
8550
Marcel Holtmann181d6952020-05-06 09:57:47 +02008551 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05008552
Johan Hedberg2ff13892015-11-25 16:15:44 +02008553 hci_dev_lock(hdev);
8554
8555 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02008556 restart_le_actions(hdev);
8557 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08008558 }
8559
Johan Hedberg229ab392013-03-15 17:06:53 -05008560 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
8561
8562 new_settings(hdev, match.sk);
8563
Johan Hedberg229ab392013-03-15 17:06:53 -05008564 if (match.sk)
8565 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02008566
8567 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05008568}
8569
Johan Hedberg2ff13892015-11-25 16:15:44 +02008570void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02008571{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02008572 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02008573 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02008574
Johan Hedberg229ab392013-03-15 17:06:53 -05008575 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02008576
8577 /* If the power off is because of hdev unregistration let
8578 * use the appropriate INVALID_INDEX status. Otherwise use
8579 * NOT_POWERED. We cover both scenarios here since later in
8580 * mgmt_index_removed() any hci_conn callbacks will have already
8581 * been triggered, potentially causing misleading DISCONNECTED
8582 * status responses.
8583 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008584 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02008585 status = MGMT_STATUS_INVALID_INDEX;
8586 else
8587 status = MGMT_STATUS_NOT_POWERED;
8588
8589 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05008590
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008591 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008592 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8593 zero_cod, sizeof(zero_cod),
8594 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008595 ext_info_changed(hdev, NULL);
8596 }
Johan Hedberg229ab392013-03-15 17:06:53 -05008597
Johan Hedberg2ff13892015-11-25 16:15:44 +02008598 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02008599
8600 if (match.sk)
8601 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02008602}
Johan Hedberg73f22f62010-12-29 16:00:25 +02008603
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008604void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03008605{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008606 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008607 u8 status;
8608
Johan Hedberg333ae952015-03-17 13:48:47 +02008609 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008610 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07008611 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03008612
8613 if (err == -ERFKILL)
8614 status = MGMT_STATUS_RFKILLED;
8615 else
8616 status = MGMT_STATUS_FAILED;
8617
Johan Hedberga69e8372015-03-06 21:08:53 +02008618 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008619
8620 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03008621}
8622
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008623void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
8624 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008625{
Johan Hedberg86742e12011-11-07 23:13:38 +02008626 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008627
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008628 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008629
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008630 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02008631 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008632 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008633 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03008634 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03008635 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008636
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07008637 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02008638}
Johan Hedbergf7520542011-01-20 12:34:39 +02008639
Johan Hedbergd7b25452014-05-23 13:19:53 +03008640static u8 mgmt_ltk_type(struct smp_ltk *ltk)
8641{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03008642 switch (ltk->type) {
8643 case SMP_LTK:
8644 case SMP_LTK_SLAVE:
8645 if (ltk->authenticated)
8646 return MGMT_LTK_AUTHENTICATED;
8647 return MGMT_LTK_UNAUTHENTICATED;
8648 case SMP_LTK_P256:
8649 if (ltk->authenticated)
8650 return MGMT_LTK_P256_AUTH;
8651 return MGMT_LTK_P256_UNAUTH;
8652 case SMP_LTK_P256_DEBUG:
8653 return MGMT_LTK_P256_DEBUG;
8654 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03008655
8656 return MGMT_LTK_UNAUTHENTICATED;
8657}
8658
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008659void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008660{
8661 struct mgmt_ev_new_long_term_key ev;
8662
8663 memset(&ev, 0, sizeof(ev));
8664
Marcel Holtmann5192d302014-02-19 17:11:58 -08008665 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008666 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08008667 * to store long term keys. Their addresses will change the
8668 * next time around.
8669 *
8670 * Only when a remote device provides an identity address
8671 * make sure the long term key is stored. If the remote
8672 * identity is known, the long term keys are internally
8673 * mapped to the identity address. So allow static random
8674 * and public addresses here.
8675 */
Johan Hedbergba74b662014-02-19 14:57:45 +02008676 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8677 (key->bdaddr.b[5] & 0xc0) != 0xc0)
8678 ev.store_hint = 0x00;
8679 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008680 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02008681
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008682 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008683 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03008684 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008685 ev.key.enc_size = key->enc_size;
8686 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08008687 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008688
Johan Hedberg2ceba532014-06-16 19:25:16 +03008689 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008690 ev.key.master = 1;
8691
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008692 /* Make sure we copy only the significant bytes based on the
8693 * encryption key size, and set the rest of the value to zeroes.
8694 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02008695 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03008696 memset(ev.key.val + key->enc_size, 0,
8697 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008698
Marcel Holtmann083368f2013-10-15 14:26:29 -07008699 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03008700}
8701
Johan Hedbergcad20c22015-10-12 13:36:19 +02008702void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02008703{
8704 struct mgmt_ev_new_irk ev;
8705
8706 memset(&ev, 0, sizeof(ev));
8707
Johan Hedbergcad20c22015-10-12 13:36:19 +02008708 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08008709
Johan Hedberg95fbac82014-02-19 15:18:31 +02008710 bacpy(&ev.rpa, &irk->rpa);
8711 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
8712 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
8713 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
8714
8715 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
8716}
8717
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008718void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
8719 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008720{
8721 struct mgmt_ev_new_csrk ev;
8722
8723 memset(&ev, 0, sizeof(ev));
8724
8725 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02008726 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008727 * to store signature resolving keys. Their addresses will change
8728 * the next time around.
8729 *
8730 * Only when a remote device provides an identity address
8731 * make sure the signature resolving key is stored. So allow
8732 * static random and public addresses here.
8733 */
8734 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
8735 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
8736 ev.store_hint = 0x00;
8737 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07008738 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008739
8740 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
8741 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02008742 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07008743 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
8744
8745 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
8746}
8747
Andre Guedesffb5a8272014-07-01 18:10:11 -03008748void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03008749 u8 bdaddr_type, u8 store_hint, u16 min_interval,
8750 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008751{
8752 struct mgmt_ev_new_conn_param ev;
8753
Johan Hedbergc103aea2014-07-02 17:37:34 +03008754 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8755 return;
8756
Andre Guedesffb5a8272014-07-01 18:10:11 -03008757 memset(&ev, 0, sizeof(ev));
8758 bacpy(&ev.addr.bdaddr, bdaddr);
8759 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008760 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008761 ev.min_interval = cpu_to_le16(min_interval);
8762 ev.max_interval = cpu_to_le16(max_interval);
8763 ev.latency = cpu_to_le16(latency);
8764 ev.timeout = cpu_to_le16(timeout);
8765
8766 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8767}
8768
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008769void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
Yu Liu1c6ed312021-04-09 15:04:06 -07008770 u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008771{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008772 char buf[512];
8773 struct mgmt_ev_device_connected *ev = (void *) buf;
8774 u16 eir_len = 0;
Yu Liu1c6ed312021-04-09 15:04:06 -07008775 u32 flags = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008776
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008777 bacpy(&ev->addr.bdaddr, &conn->dst);
8778 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008779
Yu Liu1c6ed312021-04-09 15:04:06 -07008780 if (conn->out)
8781 flags |= MGMT_DEV_FOUND_INITIATED_CONN;
8782
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008783 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008784
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008785 /* We must ensure that the EIR Data fields are ordered and
8786 * unique. Keep it simple for now and avoid the problem by not
8787 * adding any BR/EDR data to the LE adv.
8788 */
8789 if (conn->le_adv_data_len > 0) {
8790 memcpy(&ev->eir[eir_len],
8791 conn->le_adv_data, conn->le_adv_data_len);
8792 eir_len = conn->le_adv_data_len;
8793 } else {
8794 if (name_len > 0)
8795 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8796 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008797
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008798 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008799 eir_len = eir_append_data(ev->eir, eir_len,
8800 EIR_CLASS_OF_DEV,
8801 conn->dev_class, 3);
8802 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008803
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008804 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008805
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008806 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8807 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008808}
8809
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008810static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008811{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008812 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008813
Johan Hedbergf5818c22014-12-05 13:36:02 +02008814 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008815
8816 *sk = cmd->sk;
8817 sock_hold(*sk);
8818
Johan Hedberga664b5b2011-02-19 12:06:02 -03008819 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008820}
8821
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008822static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008823{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008824 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008825 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008826
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008827 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8828
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008829 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008830 mgmt_pending_remove(cmd);
8831}
8832
Johan Hedberg84c61d92014-08-01 11:13:30 +03008833bool mgmt_powering_down(struct hci_dev *hdev)
8834{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008835 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008836 struct mgmt_mode *cp;
8837
Johan Hedberg333ae952015-03-17 13:48:47 +02008838 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008839 if (!cmd)
8840 return false;
8841
8842 cp = cmd->param;
8843 if (!cp->val)
8844 return true;
8845
8846 return false;
8847}
8848
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008849void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008850 u8 link_type, u8 addr_type, u8 reason,
8851 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008852{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008853 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008854 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008855
Johan Hedberg84c61d92014-08-01 11:13:30 +03008856 /* The connection is still in hci_conn_hash so test for 1
8857 * instead of 0 to know if this is the last one.
8858 */
8859 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8860 cancel_delayed_work(&hdev->power_off);
8861 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008862 }
8863
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008864 if (!mgmt_connected)
8865 return;
8866
Andre Guedes57eb7762013-10-30 19:01:41 -03008867 if (link_type != ACL_LINK && link_type != LE_LINK)
8868 return;
8869
Johan Hedberg744cf192011-11-08 20:40:14 +02008870 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008871
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008872 bacpy(&ev.addr.bdaddr, bdaddr);
8873 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8874 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008875
Abhishek Pandit-Subedif0cfc482020-09-11 14:07:12 -07008876 /* Report disconnects due to suspend */
8877 if (hdev->suspended)
8878 ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
8879
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008880 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008881
8882 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008883 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008884
Johan Hedberg124f6e32012-02-09 13:50:12 +02008885 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008886 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008887}
8888
Marcel Holtmann78929242013-10-06 23:55:47 -07008889void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8890 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008891{
Andre Guedes3655bba2013-10-30 19:01:40 -03008892 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8893 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008894 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008895
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008896 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8897 hdev);
8898
Johan Hedberg333ae952015-03-17 13:48:47 +02008899 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008900 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008901 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008902
Andre Guedes3655bba2013-10-30 19:01:40 -03008903 cp = cmd->param;
8904
8905 if (bacmp(bdaddr, &cp->addr.bdaddr))
8906 return;
8907
8908 if (cp->addr.type != bdaddr_type)
8909 return;
8910
Johan Hedbergf5818c22014-12-05 13:36:02 +02008911 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008912 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008913}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008914
Marcel Holtmann445608d2013-10-06 23:55:48 -07008915void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8916 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008917{
8918 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008919
Johan Hedberg84c61d92014-08-01 11:13:30 +03008920 /* The connection is still in hci_conn_hash so test for 1
8921 * instead of 0 to know if this is the last one.
8922 */
8923 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8924 cancel_delayed_work(&hdev->power_off);
8925 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008926 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008927
Johan Hedberg4c659c32011-11-07 23:13:39 +02008928 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008929 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008930 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008931
Marcel Holtmann445608d2013-10-06 23:55:48 -07008932 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008933}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008934
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008935void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008936{
8937 struct mgmt_ev_pin_code_request ev;
8938
Johan Hedbergd8457692012-02-17 14:24:57 +02008939 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008940 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008941 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008942
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008943 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008944}
8945
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008946void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8947 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008948{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008949 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008950
Johan Hedberg333ae952015-03-17 13:48:47 +02008951 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008952 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008953 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008954
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008955 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008956 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008957}
8958
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008959void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8960 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008961{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008962 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008963
Johan Hedberg333ae952015-03-17 13:48:47 +02008964 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008965 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008966 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008967
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008968 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008969 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008970}
Johan Hedberga5c29682011-02-19 12:05:57 -03008971
Johan Hedberg744cf192011-11-08 20:40:14 +02008972int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008973 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008974 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008975{
8976 struct mgmt_ev_user_confirm_request ev;
8977
Marcel Holtmann181d6952020-05-06 09:57:47 +02008978 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008979
Johan Hedberg272d90d2012-02-09 15:26:12 +02008980 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008981 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008982 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008983 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008984
Johan Hedberg744cf192011-11-08 20:40:14 +02008985 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008986 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008987}
8988
Johan Hedberg272d90d2012-02-09 15:26:12 +02008989int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008990 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008991{
8992 struct mgmt_ev_user_passkey_request ev;
8993
Marcel Holtmann181d6952020-05-06 09:57:47 +02008994 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008995
Johan Hedberg272d90d2012-02-09 15:26:12 +02008996 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008997 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008998
8999 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009000 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08009001}
9002
Brian Gix0df4c182011-11-16 13:53:13 -08009003static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03009004 u8 link_type, u8 addr_type, u8 status,
9005 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03009006{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009007 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03009008
Johan Hedberg333ae952015-03-17 13:48:47 +02009009 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03009010 if (!cmd)
9011 return -ENOENT;
9012
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009013 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03009014 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03009015
Johan Hedberg7776d1d2014-12-05 13:36:03 +02009016 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03009017}
9018
Johan Hedberg744cf192011-11-08 20:40:14 +02009019int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009020 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009021{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009022 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009023 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009024}
9025
Johan Hedberg272d90d2012-02-09 15:26:12 +02009026int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009027 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03009028{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009029 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009030 status,
9031 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03009032}
Johan Hedberg2a611692011-02-19 12:06:00 -03009033
Brian Gix604086b2011-11-23 08:28:33 -08009034int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009035 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009036{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009037 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009038 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009039}
9040
Johan Hedberg272d90d2012-02-09 15:26:12 +02009041int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009042 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08009043{
Johan Hedberg272d90d2012-02-09 15:26:12 +02009044 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03009045 status,
9046 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08009047}
9048
Johan Hedberg92a25252012-09-06 18:39:26 +03009049int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
9050 u8 link_type, u8 addr_type, u32 passkey,
9051 u8 entered)
9052{
9053 struct mgmt_ev_passkey_notify ev;
9054
Marcel Holtmann181d6952020-05-06 09:57:47 +02009055 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03009056
9057 bacpy(&ev.addr.bdaddr, bdaddr);
9058 ev.addr.type = link_to_bdaddr(link_type, addr_type);
9059 ev.passkey = __cpu_to_le32(passkey);
9060 ev.entered = entered;
9061
9062 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
9063}
9064
Johan Hedberge1e930f2014-09-08 17:09:49 -07009065void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03009066{
9067 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009068 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07009069 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03009070
Johan Hedberge1e930f2014-09-08 17:09:49 -07009071 bacpy(&ev.addr.bdaddr, &conn->dst);
9072 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
9073 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03009074
Johan Hedberge1e930f2014-09-08 17:09:49 -07009075 cmd = find_pairing(conn);
9076
9077 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
9078 cmd ? cmd->sk : NULL);
9079
Johan Hedberga511b352014-12-11 21:45:45 +02009080 if (cmd) {
9081 cmd->cmd_complete(cmd, status);
9082 mgmt_pending_remove(cmd);
9083 }
Johan Hedberg2a611692011-02-19 12:06:00 -03009084}
Johan Hedbergb312b1612011-03-16 14:29:37 +02009085
Marcel Holtmann464996a2013-10-15 14:26:24 -07009086void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009087{
9088 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07009089 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009090
9091 if (status) {
9092 u8 mgmt_err = mgmt_status(status);
9093 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009094 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009095 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009096 }
9097
Marcel Holtmann464996a2013-10-15 14:26:24 -07009098 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07009099 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07009100 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009101 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02009102
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009103 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009104 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009105
Johan Hedberg47990ea2012-02-22 11:58:37 +02009106 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07009107 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009108
9109 if (match.sk)
9110 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02009111}
9112
Johan Hedberg890ea892013-03-15 17:06:52 -05009113static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02009114{
Johan Hedberg890ea892013-03-15 17:06:52 -05009115 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009116 struct hci_cp_write_eir cp;
9117
Johan Hedberg976eb202012-10-24 21:12:01 +03009118 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05009119 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02009120
Johan Hedbergc80da272012-02-22 15:38:48 +02009121 memset(hdev->eir, 0, sizeof(hdev->eir));
9122
Johan Hedbergcacaf522012-02-21 00:52:42 +02009123 memset(&cp, 0, sizeof(cp));
9124
Johan Hedberg890ea892013-03-15 17:06:52 -05009125 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02009126}
9127
Marcel Holtmann3e248562013-10-15 14:26:25 -07009128void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009129{
9130 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05009131 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009132 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009133
9134 if (status) {
9135 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009136
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009137 if (enable && hci_dev_test_and_clear_flag(hdev,
9138 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009139 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009140 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009141 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009142
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009143 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
9144 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07009145 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009146 }
9147
9148 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07009149 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009150 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009151 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009152 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07009153 changed = hci_dev_test_and_clear_flag(hdev,
9154 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07009155 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07009156 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009157 }
9158
9159 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
9160
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02009161 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07009162 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009163
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02009164 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009165 sock_put(match.sk);
9166
Johan Hedberg890ea892013-03-15 17:06:52 -05009167 hci_req_init(&req, hdev);
9168
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009169 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
9170 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03009171 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
9172 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02009173 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009174 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05009175 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03009176 }
Johan Hedberg890ea892013-03-15 17:06:52 -05009177
9178 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02009179}
9180
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009181static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02009182{
9183 struct cmd_lookup *match = data;
9184
Johan Hedberg90e70452012-02-23 23:09:40 +02009185 if (match->sk == NULL) {
9186 match->sk = cmd->sk;
9187 sock_hold(match->sk);
9188 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009189}
9190
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07009191void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
9192 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009193{
Johan Hedberg90e70452012-02-23 23:09:40 +02009194 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009195
Johan Hedberg92da6092013-03-15 17:06:55 -05009196 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
9197 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
9198 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02009199
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009200 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009201 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
9202 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009203 ext_info_changed(hdev, NULL);
9204 }
Johan Hedberg90e70452012-02-23 23:09:40 +02009205
9206 if (match.sk)
9207 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01009208}
9209
Marcel Holtmann7667da32013-10-15 14:26:27 -07009210void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02009211{
Johan Hedbergb312b1612011-03-16 14:29:37 +02009212 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02009213 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009214
Johan Hedberg13928972013-03-15 17:07:00 -05009215 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07009216 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009217
9218 memset(&ev, 0, sizeof(ev));
9219 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02009220 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009221
Johan Hedberg333ae952015-03-17 13:48:47 +02009222 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05009223 if (!cmd) {
9224 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02009225
Johan Hedberg13928972013-03-15 17:07:00 -05009226 /* If this is a HCI command related to powering on the
9227 * HCI dev don't send any mgmt signals.
9228 */
Johan Hedberg333ae952015-03-17 13:48:47 +02009229 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07009230 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02009231 }
9232
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02009233 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
9234 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02009235 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02009236}
Szymon Jancc35938b2011-03-22 13:12:21 +01009237
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009238static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
9239{
9240 int i;
9241
9242 for (i = 0; i < uuid_count; i++) {
9243 if (!memcmp(uuid, uuids[i], 16))
9244 return true;
9245 }
9246
9247 return false;
9248}
9249
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009250static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
9251{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009252 u16 parsed = 0;
9253
9254 while (parsed < eir_len) {
9255 u8 field_len = eir[0];
9256 u8 uuid[16];
9257 int i;
9258
9259 if (field_len == 0)
9260 break;
9261
9262 if (eir_len - parsed < field_len + 1)
9263 break;
9264
9265 switch (eir[1]) {
9266 case EIR_UUID16_ALL:
9267 case EIR_UUID16_SOME:
9268 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009269 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009270 uuid[13] = eir[i + 3];
9271 uuid[12] = eir[i + 2];
9272 if (has_uuid(uuid, uuid_count, uuids))
9273 return true;
9274 }
9275 break;
9276 case EIR_UUID32_ALL:
9277 case EIR_UUID32_SOME:
9278 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02009279 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01009280 uuid[15] = eir[i + 5];
9281 uuid[14] = eir[i + 4];
9282 uuid[13] = eir[i + 3];
9283 uuid[12] = eir[i + 2];
9284 if (has_uuid(uuid, uuid_count, uuids))
9285 return true;
9286 }
9287 break;
9288 case EIR_UUID128_ALL:
9289 case EIR_UUID128_SOME:
9290 for (i = 0; i + 17 <= field_len; i += 16) {
9291 memcpy(uuid, eir + i + 2, 16);
9292 if (has_uuid(uuid, uuid_count, uuids))
9293 return true;
9294 }
9295 break;
9296 }
9297
9298 parsed += field_len + 1;
9299 eir += field_len + 1;
9300 }
9301
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009302 return false;
9303}
9304
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009305static void restart_le_scan(struct hci_dev *hdev)
9306{
9307 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07009308 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009309 return;
9310
9311 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
9312 hdev->discovery.scan_start +
9313 hdev->discovery.scan_duration))
9314 return;
9315
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02009316 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009317 DISCOV_LE_RESTART_DELAY);
9318}
9319
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009320static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
9321 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
9322{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009323 /* If a RSSI threshold has been specified, and
9324 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
9325 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
9326 * is set, let it through for further processing, as we might need to
9327 * restart the scan.
9328 *
9329 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
9330 * the results are also dropped.
9331 */
9332 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9333 (rssi == HCI_RSSI_INVALID ||
9334 (rssi < hdev->discovery.rssi &&
9335 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
9336 return false;
9337
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009338 if (hdev->discovery.uuid_count != 0) {
9339 /* If a list of UUIDs is provided in filter, results with no
9340 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009341 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009342 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
9343 hdev->discovery.uuids) &&
9344 !eir_has_uuids(scan_rsp, scan_rsp_len,
9345 hdev->discovery.uuid_count,
9346 hdev->discovery.uuids))
9347 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009348 }
9349
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009350 /* If duplicate filtering does not report RSSI changes, then restart
9351 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009352 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08009353 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
9354 restart_le_scan(hdev);
9355
9356 /* Validate RSSI value against the RSSI threshold once more. */
9357 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
9358 rssi < hdev->discovery.rssi)
9359 return false;
9360 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009361
9362 return true;
9363}
9364
Marcel Holtmann901801b2013-10-06 23:55:51 -07009365void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02009366 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
9367 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03009368{
Johan Hedberge319d2e2012-01-15 19:51:59 +02009369 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009370 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02009371 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03009372
Johan Hedberg75ce2082014-07-02 22:42:01 +03009373 /* Don't send events for a non-kernel initiated discovery. With
9374 * LE one exception is if we have pend_le_reports > 0 in which
9375 * case we're doing passive scanning and want these events.
9376 */
9377 if (!hci_discovery_active(hdev)) {
9378 if (link_type == ACL_LINK)
9379 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009380 if (link_type == LE_LINK &&
9381 list_empty(&hdev->pend_le_reports) &&
9382 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03009383 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02009384 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03009385 }
Andre Guedes12602d02013-04-30 15:29:40 -03009386
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08009387 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009388 /* We are using service discovery */
9389 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
9390 scan_rsp_len))
9391 return;
9392 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01009393
Johan Hedberg78b781c2016-01-05 13:19:32 +02009394 if (hdev->discovery.limited) {
9395 /* Check for limited discoverable bit */
9396 if (dev_class) {
9397 if (!(dev_class[1] & 0x20))
9398 return;
9399 } else {
9400 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
9401 if (!flags || !(flags[0] & LE_AD_LIMITED))
9402 return;
9403 }
9404 }
9405
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009406 /* Make sure that the buffer is big enough. The 5 extra bytes
9407 * are for the potential CoD field.
9408 */
9409 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07009410 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03009411
Johan Hedberg1dc06092012-01-15 21:01:23 +02009412 memset(buf, 0, sizeof(buf));
9413
Marcel Holtmannda25cf62014-12-05 13:03:35 +01009414 /* In case of device discovery with BR/EDR devices (pre 1.2), the
9415 * RSSI value was reported as 0 when not available. This behavior
9416 * is kept when using device discovery. This is required for full
9417 * backwards compatibility with the API.
9418 *
9419 * However when using service discovery, the value 127 will be
9420 * returned when the RSSI is not available.
9421 */
Szymon Janc91200e92015-01-22 16:57:05 +01009422 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
9423 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01009424 rssi = 0;
9425
Johan Hedberg841c5642014-07-07 12:45:54 +03009426 bacpy(&ev->addr.bdaddr, bdaddr);
9427 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02009428 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02009429 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03009430
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009431 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009432 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02009433 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03009434
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02009435 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
9436 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02009437 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009438 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02009439
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08009440 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01009441 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009442 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08009443
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02009444 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
9445 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03009446
Marcel Holtmann901801b2013-10-06 23:55:51 -07009447 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03009448}
Johan Hedberga88a9652011-03-30 13:18:12 +03009449
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009450void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
9451 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03009452{
Johan Hedbergb644ba32012-01-17 21:48:47 +02009453 struct mgmt_ev_device_found *ev;
9454 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
9455 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03009456
Johan Hedbergb644ba32012-01-17 21:48:47 +02009457 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03009458
Johan Hedbergb644ba32012-01-17 21:48:47 +02009459 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03009460
Johan Hedbergb644ba32012-01-17 21:48:47 +02009461 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03009462 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009463 ev->rssi = rssi;
9464
9465 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03009466 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009467
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02009468 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02009469
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07009470 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03009471}
Johan Hedberg314b2382011-04-27 10:29:57 -04009472
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009473void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04009474{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009475 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02009476
Marcel Holtmann181d6952020-05-06 09:57:47 +02009477 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03009478
Johan Hedbergf963e8e2012-02-20 23:30:44 +02009479 memset(&ev, 0, sizeof(ev));
9480 ev.type = hdev->discovery.type;
9481 ev.discovering = discovering;
9482
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07009483 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04009484}
Antti Julku5e762442011-08-25 16:48:02 +03009485
Abhishek Pandit-Subedi346ce5b2020-09-11 14:07:11 -07009486void mgmt_suspending(struct hci_dev *hdev, u8 state)
9487{
9488 struct mgmt_ev_controller_suspend ev;
9489
9490 ev.suspend_state = state;
9491 mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
9492}
9493
9494void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
9495 u8 addr_type)
9496{
9497 struct mgmt_ev_controller_resume ev;
9498
9499 ev.wake_reason = reason;
9500 if (bdaddr) {
9501 bacpy(&ev.addr.bdaddr, bdaddr);
9502 ev.addr.type = addr_type;
9503 } else {
9504 memset(&ev.addr, 0, sizeof(ev.addr));
9505 }
9506
9507 mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
9508}
9509
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009510static struct hci_mgmt_chan chan = {
9511 .channel = HCI_CHANNEL_CONTROL,
9512 .handler_count = ARRAY_SIZE(mgmt_handlers),
9513 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02009514 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02009515};
9516
9517int mgmt_init(void)
9518{
9519 return hci_mgmt_chan_register(&chan);
9520}
9521
9522void mgmt_exit(void)
9523{
9524 hci_mgmt_chan_unregister(&chan);
9525}