blob: 8aec7fbe9a38258d7c13844084a4f3e3aeaab9a8 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Alain Michaud17896402020-06-11 02:01:57 +000039#include "mgmt_config.h"
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +020040#include "msft.h"
Johan Hedberg03811012010-12-08 00:21:06 +020041
Johan Hedberg2da9c552012-02-17 14:39:28 +020042#define MGMT_VERSION 1
Marcel Holtmann3679fe72020-04-03 21:44:06 +020043#define MGMT_REVISION 17
Johan Hedberg02d98122010-12-13 21:07:04 +020044
Johan Hedberge70bb2e2012-02-13 16:59:33 +020045static const u16 mgmt_commands[] = {
46 MGMT_OP_READ_INDEX_LIST,
47 MGMT_OP_READ_INFO,
48 MGMT_OP_SET_POWERED,
49 MGMT_OP_SET_DISCOVERABLE,
50 MGMT_OP_SET_CONNECTABLE,
51 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030052 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020053 MGMT_OP_SET_LINK_SECURITY,
54 MGMT_OP_SET_SSP,
55 MGMT_OP_SET_HS,
56 MGMT_OP_SET_LE,
57 MGMT_OP_SET_DEV_CLASS,
58 MGMT_OP_SET_LOCAL_NAME,
59 MGMT_OP_ADD_UUID,
60 MGMT_OP_REMOVE_UUID,
61 MGMT_OP_LOAD_LINK_KEYS,
62 MGMT_OP_LOAD_LONG_TERM_KEYS,
63 MGMT_OP_DISCONNECT,
64 MGMT_OP_GET_CONNECTIONS,
65 MGMT_OP_PIN_CODE_REPLY,
66 MGMT_OP_PIN_CODE_NEG_REPLY,
67 MGMT_OP_SET_IO_CAPABILITY,
68 MGMT_OP_PAIR_DEVICE,
69 MGMT_OP_CANCEL_PAIR_DEVICE,
70 MGMT_OP_UNPAIR_DEVICE,
71 MGMT_OP_USER_CONFIRM_REPLY,
72 MGMT_OP_USER_CONFIRM_NEG_REPLY,
73 MGMT_OP_USER_PASSKEY_REPLY,
74 MGMT_OP_USER_PASSKEY_NEG_REPLY,
75 MGMT_OP_READ_LOCAL_OOB_DATA,
76 MGMT_OP_ADD_REMOTE_OOB_DATA,
77 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
78 MGMT_OP_START_DISCOVERY,
79 MGMT_OP_STOP_DISCOVERY,
80 MGMT_OP_CONFIRM_NAME,
81 MGMT_OP_BLOCK_DEVICE,
82 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070083 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030084 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030085 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070086 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070087 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080088 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080089 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020090 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020091 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020092 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030093 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020094 MGMT_OP_ADD_DEVICE,
95 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030096 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020097 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020098 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020099 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200100 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100101 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700102 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700103 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700104 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700105 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700106 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100107 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200108 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200109 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200110 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000111 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000112 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200113 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200114 MGMT_OP_READ_EXP_FEATURES_INFO,
115 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000116 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
117 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200118 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
119 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200120 MGMT_OP_GET_DEVICE_FLAGS,
121 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200122 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200123};
124
125static const u16 mgmt_events[] = {
126 MGMT_EV_CONTROLLER_ERROR,
127 MGMT_EV_INDEX_ADDED,
128 MGMT_EV_INDEX_REMOVED,
129 MGMT_EV_NEW_SETTINGS,
130 MGMT_EV_CLASS_OF_DEV_CHANGED,
131 MGMT_EV_LOCAL_NAME_CHANGED,
132 MGMT_EV_NEW_LINK_KEY,
133 MGMT_EV_NEW_LONG_TERM_KEY,
134 MGMT_EV_DEVICE_CONNECTED,
135 MGMT_EV_DEVICE_DISCONNECTED,
136 MGMT_EV_CONNECT_FAILED,
137 MGMT_EV_PIN_CODE_REQUEST,
138 MGMT_EV_USER_CONFIRM_REQUEST,
139 MGMT_EV_USER_PASSKEY_REQUEST,
140 MGMT_EV_AUTH_FAILED,
141 MGMT_EV_DEVICE_FOUND,
142 MGMT_EV_DISCOVERING,
143 MGMT_EV_DEVICE_BLOCKED,
144 MGMT_EV_DEVICE_UNBLOCKED,
145 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300146 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800147 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700148 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200149 MGMT_EV_DEVICE_ADDED,
150 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300151 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200152 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200153 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200154 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700155 MGMT_EV_EXT_INDEX_ADDED,
156 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700157 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700158 MGMT_EV_ADVERTISING_ADDED,
159 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200160 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200161 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200162 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200163 MGMT_EV_DEVICE_FLAGS_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200164};
165
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700166static const u16 mgmt_untrusted_commands[] = {
167 MGMT_OP_READ_INDEX_LIST,
168 MGMT_OP_READ_INFO,
169 MGMT_OP_READ_UNCONF_INDEX_LIST,
170 MGMT_OP_READ_CONFIG_INFO,
171 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200172 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200173 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200174 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000175 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200176 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700177};
178
179static const u16 mgmt_untrusted_events[] = {
180 MGMT_EV_INDEX_ADDED,
181 MGMT_EV_INDEX_REMOVED,
182 MGMT_EV_NEW_SETTINGS,
183 MGMT_EV_CLASS_OF_DEV_CHANGED,
184 MGMT_EV_LOCAL_NAME_CHANGED,
185 MGMT_EV_UNCONF_INDEX_ADDED,
186 MGMT_EV_UNCONF_INDEX_REMOVED,
187 MGMT_EV_NEW_CONFIG_OPTIONS,
188 MGMT_EV_EXT_INDEX_ADDED,
189 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200190 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200191 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700192};
193
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800194#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200195
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200196#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
197 "\x00\x00\x00\x00\x00\x00\x00\x00"
198
Johan Hedbergca69b792011-11-11 18:10:00 +0200199/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000200static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200201 MGMT_STATUS_SUCCESS,
202 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
203 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
204 MGMT_STATUS_FAILED, /* Hardware Failure */
205 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
206 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200207 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200208 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
209 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
210 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
211 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
212 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
213 MGMT_STATUS_BUSY, /* Command Disallowed */
214 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
215 MGMT_STATUS_REJECTED, /* Rejected Security */
216 MGMT_STATUS_REJECTED, /* Rejected Personal */
217 MGMT_STATUS_TIMEOUT, /* Host Timeout */
218 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
219 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
220 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
221 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
222 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
223 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
224 MGMT_STATUS_BUSY, /* Repeated Attempts */
225 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
226 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
227 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
228 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
229 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
230 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
231 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
232 MGMT_STATUS_FAILED, /* Unspecified Error */
233 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
234 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
235 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
236 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
237 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
238 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
239 MGMT_STATUS_FAILED, /* Unit Link Key Used */
240 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
241 MGMT_STATUS_TIMEOUT, /* Instant Passed */
242 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
243 MGMT_STATUS_FAILED, /* Transaction Collision */
244 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
245 MGMT_STATUS_REJECTED, /* QoS Rejected */
246 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
247 MGMT_STATUS_REJECTED, /* Insufficient Security */
248 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
249 MGMT_STATUS_BUSY, /* Role Switch Pending */
250 MGMT_STATUS_FAILED, /* Slot Violation */
251 MGMT_STATUS_FAILED, /* Role Switch Failed */
252 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
253 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
254 MGMT_STATUS_BUSY, /* Host Busy Pairing */
255 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
256 MGMT_STATUS_BUSY, /* Controller Busy */
257 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
258 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
259 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
260 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
261 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
262};
263
264static u8 mgmt_status(u8 hci_status)
265{
266 if (hci_status < ARRAY_SIZE(mgmt_status_table))
267 return mgmt_status_table[hci_status];
268
269 return MGMT_STATUS_FAILED;
270}
271
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700272static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
273 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700274{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700275 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
276 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700277}
278
Marcel Holtmann72000df2015-03-16 16:11:21 -0700279static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
280 u16 len, int flag, struct sock *skip_sk)
281{
282 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
283 flag, skip_sk);
284}
285
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200286static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
287 struct sock *skip_sk)
288{
289 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700290 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200291}
292
Johan Hedberg85813a72015-10-21 18:02:59 +0300293static u8 le_addr_type(u8 mgmt_addr_type)
294{
295 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
296 return ADDR_LE_DEV_PUBLIC;
297 else
298 return ADDR_LE_DEV_RANDOM;
299}
300
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200301void mgmt_fill_version_info(void *ver)
302{
303 struct mgmt_rp_read_version *rp = ver;
304
305 rp->version = MGMT_VERSION;
306 rp->revision = cpu_to_le16(MGMT_REVISION);
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200311{
312 struct mgmt_rp_read_version rp;
313
Marcel Holtmann181d6952020-05-06 09:57:47 +0200314 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200315
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200316 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200317
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200318 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
319 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200320}
321
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300322static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
323 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200324{
325 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700326 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200327 size_t rp_size;
328 int i, err;
329
Marcel Holtmann181d6952020-05-06 09:57:47 +0200330 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200331
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700332 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
333 num_commands = ARRAY_SIZE(mgmt_commands);
334 num_events = ARRAY_SIZE(mgmt_events);
335 } else {
336 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
337 num_events = ARRAY_SIZE(mgmt_untrusted_events);
338 }
339
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200340 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
341
342 rp = kmalloc(rp_size, GFP_KERNEL);
343 if (!rp)
344 return -ENOMEM;
345
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700346 rp->num_commands = cpu_to_le16(num_commands);
347 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200348
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700349 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
350 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200351
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700352 for (i = 0; i < num_commands; i++, opcode++)
353 put_unaligned_le16(mgmt_commands[i], opcode);
354
355 for (i = 0; i < num_events; i++, opcode++)
356 put_unaligned_le16(mgmt_events[i], opcode);
357 } else {
358 __le16 *opcode = rp->opcodes;
359
360 for (i = 0; i < num_commands; i++, opcode++)
361 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
362
363 for (i = 0; i < num_events; i++, opcode++)
364 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
365 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200366
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200367 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
368 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200369 kfree(rp);
370
371 return err;
372}
373
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300374static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
375 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200376{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200377 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200378 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200379 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300381 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200382
Marcel Holtmann181d6952020-05-06 09:57:47 +0200383 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200384
385 read_lock(&hci_dev_list_lock);
386
387 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300388 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200389 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700390 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700391 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200392 }
393
Johan Hedberga38528f2011-01-22 06:46:43 +0200394 rp_len = sizeof(*rp) + (2 * count);
395 rp = kmalloc(rp_len, GFP_ATOMIC);
396 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100397 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200398 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100399 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberg476e44c2012-10-19 20:10:46 +0300401 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200402 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700403 if (hci_dev_test_flag(d, HCI_SETUP) ||
404 hci_dev_test_flag(d, HCI_CONFIG) ||
405 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200406 continue;
407
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200408 /* Devices marked as raw-only are neither configured
409 * nor unconfigured controllers.
410 */
411 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700412 continue;
413
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200414 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700415 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700416 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200417 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700418 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200419 }
420
Johan Hedberg476e44c2012-10-19 20:10:46 +0300421 rp->num_controllers = cpu_to_le16(count);
422 rp_len = sizeof(*rp) + (2 * count);
423
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200424 read_unlock(&hci_dev_list_lock);
425
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200426 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
427 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428
Johan Hedberga38528f2011-01-22 06:46:43 +0200429 kfree(rp);
430
431 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200432}
433
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200434static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
435 void *data, u16 data_len)
436{
437 struct mgmt_rp_read_unconf_index_list *rp;
438 struct hci_dev *d;
439 size_t rp_len;
440 u16 count;
441 int err;
442
Marcel Holtmann181d6952020-05-06 09:57:47 +0200443 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200444
445 read_lock(&hci_dev_list_lock);
446
447 count = 0;
448 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200449 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700450 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200451 count++;
452 }
453
454 rp_len = sizeof(*rp) + (2 * count);
455 rp = kmalloc(rp_len, GFP_ATOMIC);
456 if (!rp) {
457 read_unlock(&hci_dev_list_lock);
458 return -ENOMEM;
459 }
460
461 count = 0;
462 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700463 if (hci_dev_test_flag(d, HCI_SETUP) ||
464 hci_dev_test_flag(d, HCI_CONFIG) ||
465 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200466 continue;
467
468 /* Devices marked as raw-only are neither configured
469 * nor unconfigured controllers.
470 */
471 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
472 continue;
473
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200474 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700475 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200476 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200477 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200478 }
479 }
480
481 rp->num_controllers = cpu_to_le16(count);
482 rp_len = sizeof(*rp) + (2 * count);
483
484 read_unlock(&hci_dev_list_lock);
485
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200486 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
487 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200488
489 kfree(rp);
490
491 return err;
492}
493
Marcel Holtmann96f14742015-03-14 19:27:57 -0700494static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
495 void *data, u16 data_len)
496{
497 struct mgmt_rp_read_ext_index_list *rp;
498 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700499 u16 count;
500 int err;
501
Marcel Holtmann181d6952020-05-06 09:57:47 +0200502 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700503
504 read_lock(&hci_dev_list_lock);
505
506 count = 0;
507 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200508 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700509 count++;
510 }
511
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600512 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700513 if (!rp) {
514 read_unlock(&hci_dev_list_lock);
515 return -ENOMEM;
516 }
517
518 count = 0;
519 list_for_each_entry(d, &hci_dev_list, list) {
520 if (hci_dev_test_flag(d, HCI_SETUP) ||
521 hci_dev_test_flag(d, HCI_CONFIG) ||
522 hci_dev_test_flag(d, HCI_USER_CHANNEL))
523 continue;
524
525 /* Devices marked as raw-only are neither configured
526 * nor unconfigured controllers.
527 */
528 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
529 continue;
530
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200531 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700532 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
533 rp->entry[count].type = 0x01;
534 else
535 rp->entry[count].type = 0x00;
536 } else if (d->dev_type == HCI_AMP) {
537 rp->entry[count].type = 0x02;
538 } else {
539 continue;
540 }
541
542 rp->entry[count].bus = d->bus;
543 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200544 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700545 }
546
547 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700548
549 read_unlock(&hci_dev_list_lock);
550
551 /* If this command is called at least once, then all the
552 * default index and unconfigured index events are disabled
553 * and from now on only extended index events are used.
554 */
555 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
556 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
557 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
558
559 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600560 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
561 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700562
563 kfree(rp);
564
565 return err;
566}
567
Marcel Holtmanndbece372014-07-04 18:11:55 +0200568static bool is_configured(struct hci_dev *hdev)
569{
570 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700571 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200572 return false;
573
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800574 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
575 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200576 !bacmp(&hdev->public_addr, BDADDR_ANY))
577 return false;
578
579 return true;
580}
581
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200582static __le32 get_missing_options(struct hci_dev *hdev)
583{
584 u32 options = 0;
585
Marcel Holtmanndbece372014-07-04 18:11:55 +0200586 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700587 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200588 options |= MGMT_OPTION_EXTERNAL_CONFIG;
589
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800590 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
591 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200592 !bacmp(&hdev->public_addr, BDADDR_ANY))
593 options |= MGMT_OPTION_PUBLIC_ADDRESS;
594
595 return cpu_to_le32(options);
596}
597
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200598static int new_options(struct hci_dev *hdev, struct sock *skip)
599{
600 __le32 options = get_missing_options(hdev);
601
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200602 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
603 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200604}
605
Marcel Holtmanndbece372014-07-04 18:11:55 +0200606static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
607{
608 __le32 options = get_missing_options(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
611 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200612}
613
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200614static int read_config_info(struct sock *sk, struct hci_dev *hdev,
615 void *data, u16 data_len)
616{
617 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200618 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200619
Marcel Holtmann181d6952020-05-06 09:57:47 +0200620 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200621
622 hci_dev_lock(hdev);
623
624 memset(&rp, 0, sizeof(rp));
625 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200626
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200627 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
628 options |= MGMT_OPTION_EXTERNAL_CONFIG;
629
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200630 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200631 options |= MGMT_OPTION_PUBLIC_ADDRESS;
632
633 rp.supported_options = cpu_to_le32(options);
634 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200635
636 hci_dev_unlock(hdev);
637
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200638 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
639 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200640}
641
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530642static u32 get_supported_phys(struct hci_dev *hdev)
643{
644 u32 supported_phys = 0;
645
646 if (lmp_bredr_capable(hdev)) {
647 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
648
649 if (hdev->features[0][0] & LMP_3SLOT)
650 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
651
652 if (hdev->features[0][0] & LMP_5SLOT)
653 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
654
655 if (lmp_edr_2m_capable(hdev)) {
656 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
657
658 if (lmp_edr_3slot_capable(hdev))
659 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
660
661 if (lmp_edr_5slot_capable(hdev))
662 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
663
664 if (lmp_edr_3m_capable(hdev)) {
665 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
666
667 if (lmp_edr_3slot_capable(hdev))
668 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
669
670 if (lmp_edr_5slot_capable(hdev))
671 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
672 }
673 }
674 }
675
676 if (lmp_le_capable(hdev)) {
677 supported_phys |= MGMT_PHY_LE_1M_TX;
678 supported_phys |= MGMT_PHY_LE_1M_RX;
679
680 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
681 supported_phys |= MGMT_PHY_LE_2M_TX;
682 supported_phys |= MGMT_PHY_LE_2M_RX;
683 }
684
685 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
686 supported_phys |= MGMT_PHY_LE_CODED_TX;
687 supported_phys |= MGMT_PHY_LE_CODED_RX;
688 }
689 }
690
691 return supported_phys;
692}
693
694static u32 get_selected_phys(struct hci_dev *hdev)
695{
696 u32 selected_phys = 0;
697
698 if (lmp_bredr_capable(hdev)) {
699 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
700
701 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
702 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
703
704 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
705 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
706
707 if (lmp_edr_2m_capable(hdev)) {
708 if (!(hdev->pkt_type & HCI_2DH1))
709 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
710
711 if (lmp_edr_3slot_capable(hdev) &&
712 !(hdev->pkt_type & HCI_2DH3))
713 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
714
715 if (lmp_edr_5slot_capable(hdev) &&
716 !(hdev->pkt_type & HCI_2DH5))
717 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
718
719 if (lmp_edr_3m_capable(hdev)) {
720 if (!(hdev->pkt_type & HCI_3DH1))
721 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
722
723 if (lmp_edr_3slot_capable(hdev) &&
724 !(hdev->pkt_type & HCI_3DH3))
725 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
726
727 if (lmp_edr_5slot_capable(hdev) &&
728 !(hdev->pkt_type & HCI_3DH5))
729 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
730 }
731 }
732 }
733
734 if (lmp_le_capable(hdev)) {
735 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
736 selected_phys |= MGMT_PHY_LE_1M_TX;
737
738 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
739 selected_phys |= MGMT_PHY_LE_1M_RX;
740
741 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
742 selected_phys |= MGMT_PHY_LE_2M_TX;
743
744 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
745 selected_phys |= MGMT_PHY_LE_2M_RX;
746
747 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
748 selected_phys |= MGMT_PHY_LE_CODED_TX;
749
750 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
751 selected_phys |= MGMT_PHY_LE_CODED_RX;
752 }
753
754 return selected_phys;
755}
756
757static u32 get_configurable_phys(struct hci_dev *hdev)
758{
759 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
760 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
761}
762
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200763static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200764{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300768 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800769 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300770 settings |= MGMT_SETTING_CONNECTABLE;
771 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200772
Andre Guedesed3fa312012-07-24 15:03:46 -0300773 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500774 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
775 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200776 settings |= MGMT_SETTING_BREDR;
777 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700778
779 if (lmp_ssp_capable(hdev)) {
780 settings |= MGMT_SETTING_SSP;
781 settings |= MGMT_SETTING_HS;
782 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800783
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800784 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800785 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000786
Alain Michaud00bce3f2020-03-05 16:14:59 +0000787 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000788 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000789 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700790 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100791
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300792 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200793 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300794 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300795 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200796 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800797 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300798 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200799
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200800 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
801 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200802 settings |= MGMT_SETTING_CONFIGURATION;
803
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530804 settings |= MGMT_SETTING_PHY_CONFIGURATION;
805
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200806 return settings;
807}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200808
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200809static u32 get_current_settings(struct hci_dev *hdev)
810{
811 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200812
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200813 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100814 settings |= MGMT_SETTING_POWERED;
815
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700816 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200817 settings |= MGMT_SETTING_CONNECTABLE;
818
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700819 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500820 settings |= MGMT_SETTING_FAST_CONNECTABLE;
821
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700822 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200823 settings |= MGMT_SETTING_DISCOVERABLE;
824
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700825 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300826 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700828 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200829 settings |= MGMT_SETTING_BREDR;
830
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700831 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200833
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700834 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200835 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200836
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700837 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200838 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200839
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700840 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200841 settings |= MGMT_SETTING_HS;
842
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700843 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300844 settings |= MGMT_SETTING_ADVERTISING;
845
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700846 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800847 settings |= MGMT_SETTING_SECURE_CONN;
848
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700849 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800850 settings |= MGMT_SETTING_DEBUG_KEYS;
851
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700852 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200853 settings |= MGMT_SETTING_PRIVACY;
854
Marcel Holtmann93690c22015-03-06 10:11:21 -0800855 /* The current setting for static address has two purposes. The
856 * first is to indicate if the static address will be used and
857 * the second is to indicate if it is actually set.
858 *
859 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700860 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800861 * address is actually used decides if the flag is set or not.
862 *
863 * For single mode LE only controllers and dual-mode controllers
864 * with BR/EDR disabled, the existence of the static address will
865 * be evaluated.
866 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700867 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700868 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800869 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
870 if (bacmp(&hdev->static_addr, BDADDR_ANY))
871 settings |= MGMT_SETTING_STATIC_ADDRESS;
872 }
873
Alain Michaud00bce3f2020-03-05 16:14:59 +0000874 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
875 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
876
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200877 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200878}
879
Johan Hedberg333ae952015-03-17 13:48:47 +0200880static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
881{
882 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
883}
884
Johan Hedberg333ae952015-03-17 13:48:47 +0200885static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
886 struct hci_dev *hdev,
887 const void *data)
888{
889 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
890}
891
Johan Hedbergf2252572015-11-18 12:49:20 +0200892u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300893{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200894 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300895
896 /* If there's a pending mgmt command the flags will not yet have
897 * their final values, so check for this first.
898 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200899 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300900 if (cmd) {
901 struct mgmt_mode *cp = cmd->param;
902 if (cp->val == 0x01)
903 return LE_AD_GENERAL;
904 else if (cp->val == 0x02)
905 return LE_AD_LIMITED;
906 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700907 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300908 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700909 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300910 return LE_AD_GENERAL;
911 }
912
913 return 0;
914}
915
Johan Hedbergf2252572015-11-18 12:49:20 +0200916bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700917{
918 struct mgmt_pending_cmd *cmd;
919
920 /* If there's a pending mgmt command the flag will not yet have
921 * it's final value, so check for this first.
922 */
923 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
924 if (cmd) {
925 struct mgmt_mode *cp = cmd->param;
926
927 return cp->val;
928 }
929
930 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
931}
932
Johan Hedberg7d785252011-12-15 00:47:39 +0200933static void service_cache_off(struct work_struct *work)
934{
935 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300936 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500937 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200938
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700939 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200940 return;
941
Johan Hedberg890ea892013-03-15 17:06:52 -0500942 hci_req_init(&req, hdev);
943
Johan Hedberg7d785252011-12-15 00:47:39 +0200944 hci_dev_lock(hdev);
945
Johan Hedbergb1a89172015-11-25 16:15:42 +0200946 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200947 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200948
949 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500950
951 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200952}
953
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200954static void rpa_expired(struct work_struct *work)
955{
956 struct hci_dev *hdev = container_of(work, struct hci_dev,
957 rpa_expired.work);
958 struct hci_request req;
959
Marcel Holtmann181d6952020-05-06 09:57:47 +0200960 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200961
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700962 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200963
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700964 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200965 return;
966
967 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200968 * controller happens in the hci_req_enable_advertising()
969 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200970 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200971 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530972 if (ext_adv_capable(hdev))
973 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
974 else
975 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200976 hci_req_run(&req, NULL);
977}
978
Johan Hedberg6a919082012-02-28 06:17:26 +0200979static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200980{
Marcel Holtmann238be782015-03-13 02:11:06 -0700981 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200982 return;
983
Johan Hedberg4f87da82012-03-02 19:55:56 +0200984 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200985 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200986
Johan Hedberg4f87da82012-03-02 19:55:56 +0200987 /* Non-mgmt controlled devices get this bit set
988 * implicitly so that pairing works for them, however
989 * for mgmt we require user-space to explicitly enable
990 * it
991 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700992 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200993}
994
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200995static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300996 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200997{
998 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200999
Marcel Holtmann181d6952020-05-06 09:57:47 +02001000 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001002 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001003
Johan Hedberg03811012010-12-08 00:21:06 +02001004 memset(&rp, 0, sizeof(rp));
1005
Johan Hedberg03811012010-12-08 00:21:06 +02001006 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001007
1008 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001009 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001010
1011 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1012 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1013
1014 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001015
1016 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001017 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001018
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001019 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001020
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001021 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1022 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001023}
1024
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001025static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1026{
1027 u16 eir_len = 0;
1028 size_t name_len;
1029
1030 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1031 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1032 hdev->dev_class, 3);
1033
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001034 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1035 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1036 hdev->appearance);
1037
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001038 name_len = strlen(hdev->dev_name);
1039 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1040 hdev->dev_name, name_len);
1041
1042 name_len = strlen(hdev->short_name);
1043 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1044 hdev->short_name, name_len);
1045
1046 return eir_len;
1047}
1048
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001049static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1050 void *data, u16 data_len)
1051{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001052 char buf[512];
1053 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001054 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001055
Marcel Holtmann181d6952020-05-06 09:57:47 +02001056 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001057
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001058 memset(&buf, 0, sizeof(buf));
1059
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001060 hci_dev_lock(hdev);
1061
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001062 bacpy(&rp->bdaddr, &hdev->bdaddr);
1063
1064 rp->version = hdev->hci_ver;
1065 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1066
1067 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1068 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001069
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001070
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001071 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001072 rp->eir_len = cpu_to_le16(eir_len);
1073
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001074 hci_dev_unlock(hdev);
1075
1076 /* If this command is called at least once, then the events
1077 * for class of device and local name changes are disabled
1078 * and only the new extended controller information event
1079 * is used.
1080 */
1081 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1082 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1083 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1084
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001085 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1086 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001087}
1088
1089static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1090{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001091 char buf[512];
1092 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1093 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001094
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001095 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001096
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001097 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1098 ev->eir_len = cpu_to_le16(eir_len);
1099
1100 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1101 sizeof(*ev) + eir_len,
1102 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001103}
1104
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001105static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001106{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001107 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001108
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001109 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1110 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001111}
1112
Marcel Holtmann1904a852015-01-11 13:50:44 -08001113static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001114{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001115 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001116
Johan Hedberga3172b72014-02-28 09:33:44 +02001117 if (hci_conn_count(hdev) == 0) {
1118 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001119 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001120 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001121}
1122
Johan Hedbergf2252572015-11-18 12:49:20 +02001123void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001124{
1125 struct mgmt_ev_advertising_added ev;
1126
1127 ev.instance = instance;
1128
1129 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1130}
1131
Johan Hedbergf2252572015-11-18 12:49:20 +02001132void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1133 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001134{
1135 struct mgmt_ev_advertising_removed ev;
1136
1137 ev.instance = instance;
1138
1139 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1140}
1141
Florian Grandel7816b822015-06-18 03:16:45 +02001142static void cancel_adv_timeout(struct hci_dev *hdev)
1143{
1144 if (hdev->adv_instance_timeout) {
1145 hdev->adv_instance_timeout = 0;
1146 cancel_delayed_work(&hdev->adv_instance_expire);
1147 }
1148}
1149
Johan Hedberg8b064a32014-02-24 14:52:22 +02001150static int clean_up_hci_state(struct hci_dev *hdev)
1151{
1152 struct hci_request req;
1153 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001154 bool discov_stopped;
1155 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001156
1157 hci_req_init(&req, hdev);
1158
1159 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1160 test_bit(HCI_PSCAN, &hdev->flags)) {
1161 u8 scan = 0x00;
1162 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1163 }
1164
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001165 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001166
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001167 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001168 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001169
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001170 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001171
1172 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001173 /* 0x15 == Terminated due to Power Off */
1174 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001175 }
1176
Johan Hedberg23a48092014-07-08 16:05:06 +03001177 err = hci_req_run(&req, clean_up_hci_complete);
1178 if (!err && discov_stopped)
1179 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1180
1181 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001182}
1183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001184static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001185 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001186{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001187 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001188 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001189 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190
Marcel Holtmann181d6952020-05-06 09:57:47 +02001191 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192
Johan Hedberga7e80f22013-01-09 16:05:19 +02001193 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001194 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1195 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001198
Johan Hedberg333ae952015-03-17 13:48:47 +02001199 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001200 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1201 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001202 goto failed;
1203 }
1204
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001205 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 goto failed;
1208 }
1209
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001210 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1211 if (!cmd) {
1212 err = -ENOMEM;
1213 goto failed;
1214 }
1215
Johan Hedberg8b064a32014-02-24 14:52:22 +02001216 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001217 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001218 err = 0;
1219 } else {
1220 /* Disconnect connections, stop scans, etc */
1221 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001222 if (!err)
1223 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1224 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001225
Johan Hedberg8b064a32014-02-24 14:52:22 +02001226 /* ENODATA means there were no HCI commands queued */
1227 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001228 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001229 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1230 err = 0;
1231 }
1232 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001233
1234failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001235 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001236 return err;
1237}
1238
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001239static int new_settings(struct hci_dev *hdev, struct sock *skip)
1240{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001241 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001242
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001243 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1244 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001245}
1246
Johan Hedberg91a668b2014-07-09 13:28:26 +03001247int mgmt_new_settings(struct hci_dev *hdev)
1248{
1249 return new_settings(hdev, NULL);
1250}
1251
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001252struct cmd_lookup {
1253 struct sock *sk;
1254 struct hci_dev *hdev;
1255 u8 mgmt_status;
1256};
1257
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001258static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001259{
1260 struct cmd_lookup *match = data;
1261
1262 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1263
1264 list_del(&cmd->list);
1265
1266 if (match->sk == NULL) {
1267 match->sk = cmd->sk;
1268 sock_hold(match->sk);
1269 }
1270
1271 mgmt_pending_free(cmd);
1272}
1273
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001274static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001275{
1276 u8 *status = data;
1277
Johan Hedberga69e8372015-03-06 21:08:53 +02001278 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001279 mgmt_pending_remove(cmd);
1280}
1281
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001282static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001283{
1284 if (cmd->cmd_complete) {
1285 u8 *status = data;
1286
1287 cmd->cmd_complete(cmd, *status);
1288 mgmt_pending_remove(cmd);
1289
1290 return;
1291 }
1292
1293 cmd_status_rsp(cmd, data);
1294}
1295
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001296static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001297{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001298 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1299 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001300}
1301
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001302static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001303{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001304 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1305 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001306}
1307
Johan Hedberge6fe7982013-10-02 15:45:22 +03001308static u8 mgmt_bredr_support(struct hci_dev *hdev)
1309{
1310 if (!lmp_bredr_capable(hdev))
1311 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001312 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001313 return MGMT_STATUS_REJECTED;
1314 else
1315 return MGMT_STATUS_SUCCESS;
1316}
1317
1318static u8 mgmt_le_support(struct hci_dev *hdev)
1319{
1320 if (!lmp_le_capable(hdev))
1321 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001322 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001323 return MGMT_STATUS_REJECTED;
1324 else
1325 return MGMT_STATUS_SUCCESS;
1326}
1327
Johan Hedbergaed1a882015-11-22 17:24:44 +03001328void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001329{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001330 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001331
Marcel Holtmann181d6952020-05-06 09:57:47 +02001332 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001333
1334 hci_dev_lock(hdev);
1335
Johan Hedberg333ae952015-03-17 13:48:47 +02001336 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001337 if (!cmd)
1338 goto unlock;
1339
1340 if (status) {
1341 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001342 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001343 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001344 goto remove_cmd;
1345 }
1346
Johan Hedbergaed1a882015-11-22 17:24:44 +03001347 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1348 hdev->discov_timeout > 0) {
1349 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1350 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001351 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001352
1353 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001354 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001355
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001356remove_cmd:
1357 mgmt_pending_remove(cmd);
1358
1359unlock:
1360 hci_dev_unlock(hdev);
1361}
1362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001363static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001364 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001365{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001366 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001367 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001368 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001369 int err;
1370
Marcel Holtmann181d6952020-05-06 09:57:47 +02001371 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001372
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001373 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1374 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001375 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1376 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001377
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001378 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001379 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1380 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001381
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001382 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001383
1384 /* Disabling discoverable requires that no timeout is set,
1385 * and enabling limited discoverable requires a timeout.
1386 */
1387 if ((cp->val == 0x00 && timeout > 0) ||
1388 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001389 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001393
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001394 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001395 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1396 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001397 goto failed;
1398 }
1399
Johan Hedberg333ae952015-03-17 13:48:47 +02001400 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1401 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001402 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1403 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001404 goto failed;
1405 }
1406
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001407 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001408 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1409 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001410 goto failed;
1411 }
1412
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001413 if (hdev->advertising_paused) {
1414 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1415 MGMT_STATUS_BUSY);
1416 goto failed;
1417 }
1418
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001419 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001420 bool changed = false;
1421
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001422 /* Setting limited discoverable when powered off is
1423 * not a valid operation since it requires a timeout
1424 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1425 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001426 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001427 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001428 changed = true;
1429 }
1430
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001431 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001432 if (err < 0)
1433 goto failed;
1434
1435 if (changed)
1436 err = new_settings(hdev, sk);
1437
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001438 goto failed;
1439 }
1440
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001441 /* If the current mode is the same, then just update the timeout
1442 * value with the new value. And if only the timeout gets updated,
1443 * then no need for any HCI transactions.
1444 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001445 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1446 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1447 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001448 cancel_delayed_work(&hdev->discov_off);
1449 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001450
Marcel Holtmann36261542013-10-15 08:28:51 -07001451 if (cp->val && hdev->discov_timeout > 0) {
1452 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001453 queue_delayed_work(hdev->req_workqueue,
1454 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001455 }
1456
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001457 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001458 goto failed;
1459 }
1460
1461 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1462 if (!cmd) {
1463 err = -ENOMEM;
1464 goto failed;
1465 }
1466
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001467 /* Cancel any potential discoverable timeout that might be
1468 * still active and store new timeout value. The arming of
1469 * the timeout happens in the complete handler.
1470 */
1471 cancel_delayed_work(&hdev->discov_off);
1472 hdev->discov_timeout = timeout;
1473
Johan Hedbergaed1a882015-11-22 17:24:44 +03001474 if (cp->val)
1475 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1476 else
1477 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1478
Johan Hedbergb456f872013-10-19 23:38:22 +03001479 /* Limited discoverable mode */
1480 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001481 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001482 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001483 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001484
Johan Hedbergaed1a882015-11-22 17:24:44 +03001485 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1486 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001487
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001488failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001489 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001490 return err;
1491}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001492
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001493void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001494{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001495 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001496
Marcel Holtmann181d6952020-05-06 09:57:47 +02001497 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001498
1499 hci_dev_lock(hdev);
1500
Johan Hedberg333ae952015-03-17 13:48:47 +02001501 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001502 if (!cmd)
1503 goto unlock;
1504
Johan Hedberg37438c12013-10-14 16:20:05 +03001505 if (status) {
1506 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001507 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001508 goto remove_cmd;
1509 }
1510
Johan Hedberg2b76f452013-03-15 17:07:04 -05001511 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001512 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001513
Johan Hedberg37438c12013-10-14 16:20:05 +03001514remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001515 mgmt_pending_remove(cmd);
1516
1517unlock:
1518 hci_dev_unlock(hdev);
1519}
1520
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001521static int set_connectable_update_settings(struct hci_dev *hdev,
1522 struct sock *sk, u8 val)
1523{
1524 bool changed = false;
1525 int err;
1526
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001527 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001528 changed = true;
1529
1530 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001531 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001532 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001533 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1534 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001535 }
1536
1537 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1538 if (err < 0)
1539 return err;
1540
Johan Hedberg562064e2014-07-08 16:35:34 +03001541 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001542 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001543 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001544 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001545 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001546
1547 return 0;
1548}
1549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001551 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001552{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001553 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001554 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001555 int err;
1556
Marcel Holtmann181d6952020-05-06 09:57:47 +02001557 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001558
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001559 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1560 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001561 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1562 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001563
Johan Hedberga7e80f22013-01-09 16:05:19 +02001564 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1566 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001568 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001569
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001570 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001571 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001572 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001573 }
1574
Johan Hedberg333ae952015-03-17 13:48:47 +02001575 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1576 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001577 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1578 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001579 goto failed;
1580 }
1581
Johan Hedberg73f22f62010-12-29 16:00:25 +02001582 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1583 if (!cmd) {
1584 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001585 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001586 }
1587
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001588 if (cp->val) {
1589 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1590 } else {
1591 if (hdev->discov_timeout > 0)
1592 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001593
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001594 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1595 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1596 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001597 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001598
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001599 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1600 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001601
1602failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001603 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001604 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001605}
1606
Johan Hedbergb2939472014-07-30 09:22:23 +03001607static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001608 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001609{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001610 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001611 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001612 int err;
1613
Marcel Holtmann181d6952020-05-06 09:57:47 +02001614 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001615
Johan Hedberga7e80f22013-01-09 16:05:19 +02001616 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001617 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1618 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001619
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001620 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001621
1622 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001623 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001624 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001625 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001626
Johan Hedbergb2939472014-07-30 09:22:23 +03001627 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001628 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001629 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001630
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001631 if (changed) {
1632 /* In limited privacy mode the change of bondable mode
1633 * may affect the local advertising address.
1634 */
1635 if (hdev_is_powered(hdev) &&
1636 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1637 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1638 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1639 queue_work(hdev->req_workqueue,
1640 &hdev->discoverable_update);
1641
Marcel Holtmann55594352013-10-06 16:11:57 -07001642 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001643 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001644
Marcel Holtmann55594352013-10-06 16:11:57 -07001645unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001646 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001647 return err;
1648}
1649
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001650static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1651 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001652{
1653 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001654 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001655 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001656 int err;
1657
Marcel Holtmann181d6952020-05-06 09:57:47 +02001658 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001659
Johan Hedberge6fe7982013-10-02 15:45:22 +03001660 status = mgmt_bredr_support(hdev);
1661 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001662 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1663 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001664
Johan Hedberga7e80f22013-01-09 16:05:19 +02001665 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001666 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1667 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001668
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001669 hci_dev_lock(hdev);
1670
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001671 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001672 bool changed = false;
1673
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001674 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001675 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001676 changed = true;
1677 }
1678
1679 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1680 if (err < 0)
1681 goto failed;
1682
1683 if (changed)
1684 err = new_settings(hdev, sk);
1685
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001686 goto failed;
1687 }
1688
Johan Hedberg333ae952015-03-17 13:48:47 +02001689 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001690 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1691 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001692 goto failed;
1693 }
1694
1695 val = !!cp->val;
1696
1697 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1698 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1699 goto failed;
1700 }
1701
1702 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1703 if (!cmd) {
1704 err = -ENOMEM;
1705 goto failed;
1706 }
1707
1708 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1709 if (err < 0) {
1710 mgmt_pending_remove(cmd);
1711 goto failed;
1712 }
1713
1714failed:
1715 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001716 return err;
1717}
1718
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001719static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001720{
1721 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001722 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001723 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001724 int err;
1725
Marcel Holtmann181d6952020-05-06 09:57:47 +02001726 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001727
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001728 status = mgmt_bredr_support(hdev);
1729 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001730 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001731
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001732 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001733 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1734 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001735
Johan Hedberga7e80f22013-01-09 16:05:19 +02001736 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001737 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1738 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001739
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001740 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001741
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001742 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001743 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001744
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001745 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001746 changed = !hci_dev_test_and_set_flag(hdev,
1747 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001748 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001749 changed = hci_dev_test_and_clear_flag(hdev,
1750 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001751 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001752 changed = hci_dev_test_and_clear_flag(hdev,
1753 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001754 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001755 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001756 }
1757
1758 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1759 if (err < 0)
1760 goto failed;
1761
1762 if (changed)
1763 err = new_settings(hdev, sk);
1764
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001765 goto failed;
1766 }
1767
Johan Hedberg333ae952015-03-17 13:48:47 +02001768 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001769 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1770 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001771 goto failed;
1772 }
1773
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001774 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001775 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1776 goto failed;
1777 }
1778
1779 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1780 if (!cmd) {
1781 err = -ENOMEM;
1782 goto failed;
1783 }
1784
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001785 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001786 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1787 sizeof(cp->val), &cp->val);
1788
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001789 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001790 if (err < 0) {
1791 mgmt_pending_remove(cmd);
1792 goto failed;
1793 }
1794
1795failed:
1796 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001797 return err;
1798}
1799
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001800static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001801{
1802 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001803 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001804 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001805 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001806
Marcel Holtmann181d6952020-05-06 09:57:47 +02001807 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001808
Johan Hedberge6fe7982013-10-02 15:45:22 +03001809 status = mgmt_bredr_support(hdev);
1810 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001811 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001812
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001813 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001814 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1815 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001817 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001818 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1819 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001820
Johan Hedberga7e80f22013-01-09 16:05:19 +02001821 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1823 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001824
Marcel Holtmannee392692013-10-01 22:59:23 -07001825 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001826
Johan Hedberg333ae952015-03-17 13:48:47 +02001827 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001828 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1829 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001830 goto unlock;
1831 }
1832
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001833 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001834 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001835 } else {
1836 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001837 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1838 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001839 goto unlock;
1840 }
1841
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001842 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001843 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001844
1845 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1846 if (err < 0)
1847 goto unlock;
1848
1849 if (changed)
1850 err = new_settings(hdev, sk);
1851
1852unlock:
1853 hci_dev_unlock(hdev);
1854 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001855}
1856
Marcel Holtmann1904a852015-01-11 13:50:44 -08001857static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001858{
1859 struct cmd_lookup match = { NULL, hdev };
1860
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301861 hci_dev_lock(hdev);
1862
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001863 if (status) {
1864 u8 mgmt_err = mgmt_status(status);
1865
1866 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1867 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301868 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001869 }
1870
1871 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1872
1873 new_settings(hdev, match.sk);
1874
1875 if (match.sk)
1876 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001877
1878 /* Make sure the controller has a good default for
1879 * advertising data. Restrict the update to when LE
1880 * has actually been enabled. During power on, the
1881 * update in powered_update_hci will take care of it.
1882 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001883 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001884 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001885 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301886 if (ext_adv_capable(hdev)) {
1887 int err;
1888
1889 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1890 if (!err)
1891 __hci_req_update_scan_rsp_data(&req, 0x00);
1892 } else {
1893 __hci_req_update_adv_data(&req, 0x00);
1894 __hci_req_update_scan_rsp_data(&req, 0x00);
1895 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001896 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001897 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001898 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301899
1900unlock:
1901 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001902}
1903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001905{
1906 struct mgmt_mode *cp = data;
1907 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001908 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001909 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001910 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001911 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001912
Marcel Holtmann181d6952020-05-06 09:57:47 +02001913 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001915 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001916 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1917 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001918
Johan Hedberga7e80f22013-01-09 16:05:19 +02001919 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001920 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1921 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001922
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001923 /* Bluetooth single mode LE only controllers or dual-mode
1924 * controllers configured as LE only devices, do not allow
1925 * switching LE off. These have either LE enabled explicitly
1926 * or BR/EDR has been previously switched off.
1927 *
1928 * When trying to enable an already enabled LE, then gracefully
1929 * send a positive response. Trying to disable it however will
1930 * result into rejection.
1931 */
1932 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1933 if (cp->val == 0x01)
1934 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1935
Johan Hedberga69e8372015-03-06 21:08:53 +02001936 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1937 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001938 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001939
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001940 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001941
1942 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001943 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944
Florian Grandel847818d2015-06-18 03:16:46 +02001945 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001946 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001947
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001948 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001949 bool changed = false;
1950
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001951 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001952 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001953 changed = true;
1954 }
1955
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001956 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001957 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001958 changed = true;
1959 }
1960
Johan Hedberg06199cf2012-02-22 16:37:11 +02001961 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1962 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001963 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001964
1965 if (changed)
1966 err = new_settings(hdev, sk);
1967
Johan Hedberg1de028c2012-02-29 19:55:35 -08001968 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969 }
1970
Johan Hedberg333ae952015-03-17 13:48:47 +02001971 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1972 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001973 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1974 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001975 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001976 }
1977
1978 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1979 if (!cmd) {
1980 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001981 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001982 }
1983
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001984 hci_req_init(&req, hdev);
1985
Johan Hedberg06199cf2012-02-22 16:37:11 +02001986 memset(&hci_cp, 0, sizeof(hci_cp));
1987
1988 if (val) {
1989 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001990 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001991 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001992 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001993 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301994
1995 if (ext_adv_capable(hdev))
1996 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001997 }
1998
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001999 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2000 &hci_cp);
2001
2002 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302003 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002004 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002005
Johan Hedberg1de028c2012-02-29 19:55:35 -08002006unlock:
2007 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002008 return err;
2009}
2010
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002011/* This is a helper function to test for pending mgmt commands that can
2012 * cause CoD or EIR HCI commands. We can only allow one such pending
2013 * mgmt command at a time since otherwise we cannot easily track what
2014 * the current values are, will be, and based on that calculate if a new
2015 * HCI command needs to be sent and if yes with what value.
2016 */
2017static bool pending_eir_or_class(struct hci_dev *hdev)
2018{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002019 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002020
2021 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2022 switch (cmd->opcode) {
2023 case MGMT_OP_ADD_UUID:
2024 case MGMT_OP_REMOVE_UUID:
2025 case MGMT_OP_SET_DEV_CLASS:
2026 case MGMT_OP_SET_POWERED:
2027 return true;
2028 }
2029 }
2030
2031 return false;
2032}
2033
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002034static const u8 bluetooth_base_uuid[] = {
2035 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2036 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2037};
2038
2039static u8 get_uuid_size(const u8 *uuid)
2040{
2041 u32 val;
2042
2043 if (memcmp(uuid, bluetooth_base_uuid, 12))
2044 return 128;
2045
2046 val = get_unaligned_le32(&uuid[12]);
2047 if (val > 0xffff)
2048 return 32;
2049
2050 return 16;
2051}
2052
Johan Hedberg92da6092013-03-15 17:06:55 -05002053static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2054{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002055 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002056
2057 hci_dev_lock(hdev);
2058
Johan Hedberg333ae952015-03-17 13:48:47 +02002059 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002060 if (!cmd)
2061 goto unlock;
2062
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002063 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2064 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002065
2066 mgmt_pending_remove(cmd);
2067
2068unlock:
2069 hci_dev_unlock(hdev);
2070}
2071
Marcel Holtmann1904a852015-01-11 13:50:44 -08002072static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002073{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002074 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002075
2076 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2077}
2078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002081 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002082 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002083 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085 int err;
2086
Marcel Holtmann181d6952020-05-06 09:57:47 +02002087 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002091 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002092 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2093 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002094 goto failed;
2095 }
2096
Andre Guedes92c4c202012-06-07 19:05:44 -03002097 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002098 if (!uuid) {
2099 err = -ENOMEM;
2100 goto failed;
2101 }
2102
2103 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002104 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002105 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002106
Johan Hedbergde66aa62013-01-27 00:31:27 +02002107 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002108
Johan Hedberg890ea892013-03-15 17:06:52 -05002109 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002110
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002111 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002112 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002113
Johan Hedberg92da6092013-03-15 17:06:55 -05002114 err = hci_req_run(&req, add_uuid_complete);
2115 if (err < 0) {
2116 if (err != -ENODATA)
2117 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002118
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002119 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2120 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002121 goto failed;
2122 }
2123
2124 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002125 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002126 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002127 goto failed;
2128 }
2129
2130 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131
2132failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002133 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134 return err;
2135}
2136
Johan Hedberg24b78d02012-02-23 23:24:30 +02002137static bool enable_service_cache(struct hci_dev *hdev)
2138{
2139 if (!hdev_is_powered(hdev))
2140 return false;
2141
Marcel Holtmann238be782015-03-13 02:11:06 -07002142 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002143 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2144 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002145 return true;
2146 }
2147
2148 return false;
2149}
2150
Marcel Holtmann1904a852015-01-11 13:50:44 -08002151static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002152{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002153 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002154
2155 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2156}
2157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002158static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002159 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002160{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002161 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002162 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002163 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 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 -05002165 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002166 int err, found;
2167
Marcel Holtmann181d6952020-05-06 09:57:47 +02002168 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002170 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002171
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002172 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002173 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2174 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002175 goto unlock;
2176 }
2177
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002178 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002179 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002180
Johan Hedberg24b78d02012-02-23 23:24:30 +02002181 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002182 err = mgmt_cmd_complete(sk, hdev->id,
2183 MGMT_OP_REMOVE_UUID,
2184 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002185 goto unlock;
2186 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002187
Johan Hedberg9246a862012-02-23 21:33:16 +02002188 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189 }
2190
2191 found = 0;
2192
Johan Hedberg056341c2013-01-27 00:31:30 +02002193 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002194 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2195 continue;
2196
2197 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002198 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 found++;
2200 }
2201
2202 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002203 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2204 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002205 goto unlock;
2206 }
2207
Johan Hedberg9246a862012-02-23 21:33:16 +02002208update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002209 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002210
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002211 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002212 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002213
Johan Hedberg92da6092013-03-15 17:06:55 -05002214 err = hci_req_run(&req, remove_uuid_complete);
2215 if (err < 0) {
2216 if (err != -ENODATA)
2217 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002218
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002219 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2220 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002221 goto unlock;
2222 }
2223
2224 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002225 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002226 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002227 goto unlock;
2228 }
2229
2230 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002231
2232unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002233 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002234 return err;
2235}
2236
Marcel Holtmann1904a852015-01-11 13:50:44 -08002237static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002238{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002239 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002240
2241 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2242}
2243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002245 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002246{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002247 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002248 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002249 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002250 int err;
2251
Marcel Holtmann181d6952020-05-06 09:57:47 +02002252 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002253
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002254 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002255 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2256 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002258 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002259
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002260 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002261 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2262 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002263 goto unlock;
2264 }
2265
2266 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002267 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2268 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002269 goto unlock;
2270 }
2271
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002272 hdev->major_class = cp->major;
2273 hdev->minor_class = cp->minor;
2274
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002275 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002276 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2277 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002278 goto unlock;
2279 }
2280
Johan Hedberg890ea892013-03-15 17:06:52 -05002281 hci_req_init(&req, hdev);
2282
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002283 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002284 hci_dev_unlock(hdev);
2285 cancel_delayed_work_sync(&hdev->service_cache);
2286 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002287 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002288 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002289
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002290 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002291
Johan Hedberg92da6092013-03-15 17:06:55 -05002292 err = hci_req_run(&req, set_class_complete);
2293 if (err < 0) {
2294 if (err != -ENODATA)
2295 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002296
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 Hedberg90e70452012-02-23 23:09:40 +02002299 goto unlock;
2300 }
2301
2302 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002303 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002304 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002305 goto unlock;
2306 }
2307
2308 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002309
Johan Hedbergb5235a62012-02-21 14:32:24 +02002310unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002311 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002312 return err;
2313}
2314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002316 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002318 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002319 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2320 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002321 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002322 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002323 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002324
Marcel Holtmann181d6952020-05-06 09:57:47 +02002325 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002326
2327 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2329 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002330
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002331 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002332 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002333 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2334 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002335 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2336 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002337 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002339 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002340 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002341 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2342 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002343 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2344 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002345 }
2346
Johan Hedberg4ae14302013-01-20 14:27:13 +02002347 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002348 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2349 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002350
Marcel Holtmann181d6952020-05-06 09:57:47 +02002351 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2352 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002354 for (i = 0; i < key_count; i++) {
2355 struct mgmt_link_key_info *key = &cp->keys[i];
2356
Marcel Holtmann8e991132014-01-10 02:07:25 -08002357 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002358 return mgmt_cmd_status(sk, hdev->id,
2359 MGMT_OP_LOAD_LINK_KEYS,
2360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002361 }
2362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002363 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364
2365 hci_link_keys_clear(hdev);
2366
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002367 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002368 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002369 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002370 changed = hci_dev_test_and_clear_flag(hdev,
2371 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002372
2373 if (changed)
2374 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002376 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002377 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378
Alain Michaud600a8742020-01-07 00:43:17 +00002379 if (hci_is_blocked_key(hdev,
2380 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2381 key->val)) {
2382 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2383 &key->addr.bdaddr);
2384 continue;
2385 }
2386
Johan Hedberg58e92932014-06-24 14:00:26 +03002387 /* Always ignore debug keys and require a new pairing if
2388 * the user wants to use them.
2389 */
2390 if (key->type == HCI_LK_DEBUG_COMBINATION)
2391 continue;
2392
Johan Hedberg7652ff62014-06-24 13:15:49 +03002393 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2394 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002395 }
2396
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002397 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002398
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002400
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002401 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002402}
2403
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002404static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002406{
2407 struct mgmt_ev_device_unpaired ev;
2408
2409 bacpy(&ev.addr.bdaddr, bdaddr);
2410 ev.addr.type = addr_type;
2411
2412 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002414}
2415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002416static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002417 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002418{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002419 struct mgmt_cp_unpair_device *cp = data;
2420 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002421 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002422 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002423 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002424 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002425 int err;
2426
Johan Hedberga8a1d192011-11-10 15:54:38 +02002427 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002428 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2429 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002430
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002431 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002432 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2433 MGMT_STATUS_INVALID_PARAMS,
2434 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002435
Johan Hedberg118da702013-01-20 14:27:20 +02002436 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002437 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2438 MGMT_STATUS_INVALID_PARAMS,
2439 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002440
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002441 hci_dev_lock(hdev);
2442
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002443 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002444 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2445 MGMT_STATUS_NOT_POWERED, &rp,
2446 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002447 goto unlock;
2448 }
2449
Johan Hedberge0b2b272014-02-18 17:14:31 +02002450 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002451 /* If disconnection is requested, then look up the
2452 * connection. If the remote device is connected, it
2453 * will be later used to terminate the link.
2454 *
2455 * Setting it to NULL explicitly will cause no
2456 * termination of the link.
2457 */
2458 if (cp->disconnect)
2459 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2460 &cp->addr.bdaddr);
2461 else
2462 conn = NULL;
2463
Johan Hedberg124f6e32012-02-09 13:50:12 +02002464 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002465 if (err < 0) {
2466 err = mgmt_cmd_complete(sk, hdev->id,
2467 MGMT_OP_UNPAIR_DEVICE,
2468 MGMT_STATUS_NOT_PAIRED, &rp,
2469 sizeof(rp));
2470 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002471 }
2472
Johan Hedbergec182f02015-10-21 18:03:03 +03002473 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002474 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002475
Johan Hedbergec182f02015-10-21 18:03:03 +03002476 /* LE address type */
2477 addr_type = le_addr_type(cp->addr.type);
2478
Matias Karhumaacb28c302018-09-26 09:13:46 +03002479 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2480 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002481 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002482 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2483 MGMT_STATUS_NOT_PAIRED, &rp,
2484 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485 goto unlock;
2486 }
2487
Johan Hedbergec182f02015-10-21 18:03:03 +03002488 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2489 if (!conn) {
2490 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2491 goto done;
2492 }
2493
Johan Hedbergc81d5552015-10-22 09:38:35 +03002494
Johan Hedbergec182f02015-10-21 18:03:03 +03002495 /* Defer clearing up the connection parameters until closing to
2496 * give a chance of keeping them if a repairing happens.
2497 */
2498 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2499
Johan Hedbergfc643612015-10-22 09:38:31 +03002500 /* Disable auto-connection parameters if present */
2501 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2502 if (params) {
2503 if (params->explicit_connect)
2504 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2505 else
2506 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2507 }
2508
Johan Hedbergec182f02015-10-21 18:03:03 +03002509 /* If disconnection is not requested, then clear the connection
2510 * variable so that the link is not terminated.
2511 */
2512 if (!cp->disconnect)
2513 conn = NULL;
2514
2515done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002516 /* If the connection variable is set, then termination of the
2517 * link is requested.
2518 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002519 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002520 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2521 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002522 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002523 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002524 }
2525
Johan Hedberg124f6e32012-02-09 13:50:12 +02002526 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002528 if (!cmd) {
2529 err = -ENOMEM;
2530 goto unlock;
2531 }
2532
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002533 cmd->cmd_complete = addr_cmd_complete;
2534
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002535 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002536 if (err < 0)
2537 mgmt_pending_remove(cmd);
2538
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002539unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002541 return err;
2542}
2543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002547 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002548 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002549 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002550 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002551 int err;
2552
Marcel Holtmann181d6952020-05-06 09:57:47 +02002553 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002554
Johan Hedberg06a63b12013-01-20 14:27:21 +02002555 memset(&rp, 0, sizeof(rp));
2556 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2557 rp.addr.type = cp->addr.type;
2558
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002559 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002560 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2561 MGMT_STATUS_INVALID_PARAMS,
2562 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002563
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002564 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565
2566 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002567 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2568 MGMT_STATUS_NOT_POWERED, &rp,
2569 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570 goto failed;
2571 }
2572
Johan Hedberg333ae952015-03-17 13:48:47 +02002573 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002574 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2575 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576 goto failed;
2577 }
2578
Andre Guedes591f47f2012-04-24 21:02:49 -03002579 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002580 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2581 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002582 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002583 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2584 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002585
Vishal Agarwalf9607272012-06-13 05:32:43 +05302586 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002587 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2588 MGMT_STATUS_NOT_CONNECTED, &rp,
2589 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002590 goto failed;
2591 }
2592
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002593 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002594 if (!cmd) {
2595 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002596 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002597 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002598
Johan Hedbergf5818c22014-12-05 13:36:02 +02002599 cmd->cmd_complete = generic_cmd_complete;
2600
Johan Hedberge3f2f922014-08-18 20:33:33 +03002601 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002602 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002603 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002604
2605failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002606 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002607 return err;
2608}
2609
Andre Guedes57c14772012-04-24 21:02:50 -03002610static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002611{
2612 switch (link_type) {
2613 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002614 switch (addr_type) {
2615 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002616 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002617
Johan Hedberg48264f02011-11-09 13:58:58 +02002618 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002619 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002620 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002621 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002622
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002624 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002625 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002626 }
2627}
2628
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002629static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2630 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002631{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002632 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002633 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002634 int err;
2635 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002636
Marcel Holtmann181d6952020-05-06 09:57:47 +02002637 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002639 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002641 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002642 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2643 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002644 goto unlock;
2645 }
2646
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002647 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002648 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2649 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002650 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002651 }
2652
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002653 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002654 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002655 err = -ENOMEM;
2656 goto unlock;
2657 }
2658
Johan Hedberg2784eb42011-01-21 13:56:35 +02002659 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002660 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002661 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2662 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002663 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002664 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002665 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002666 continue;
2667 i++;
2668 }
2669
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002670 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002671
Johan Hedberg4c659c32011-11-07 23:13:39 +02002672 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002673 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002674 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002675
Johan Hedberga38528f2011-01-22 06:46:43 +02002676 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002677
2678unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002679 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002680 return err;
2681}
2682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002683static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002684 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002685{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002686 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002687 int err;
2688
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002689 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002690 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002691 if (!cmd)
2692 return -ENOMEM;
2693
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002694 cmd->cmd_complete = addr_cmd_complete;
2695
Johan Hedbergd8457692012-02-17 14:24:57 +02002696 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002697 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002698 if (err < 0)
2699 mgmt_pending_remove(cmd);
2700
2701 return err;
2702}
2703
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002704static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002706{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002707 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002708 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002710 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711 int err;
2712
Marcel Holtmann181d6952020-05-06 09:57:47 +02002713 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002715 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002716
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002717 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002718 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2719 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720 goto failed;
2721 }
2722
Johan Hedbergd8457692012-02-17 14:24:57 +02002723 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002724 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002725 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2726 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002727 goto failed;
2728 }
2729
2730 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002731 struct mgmt_cp_pin_code_neg_reply ncp;
2732
2733 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002734
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002735 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002737 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002738 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002739 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2740 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002741
2742 goto failed;
2743 }
2744
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002745 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002746 if (!cmd) {
2747 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002748 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002749 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002750
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002751 cmd->cmd_complete = addr_cmd_complete;
2752
Johan Hedbergd8457692012-02-17 14:24:57 +02002753 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002754 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002755 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002756
2757 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2758 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002759 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002760
2761failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002762 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002763 return err;
2764}
2765
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2767 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002768{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002769 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002770
Marcel Holtmann181d6952020-05-06 09:57:47 +02002771 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002772
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002773 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002774 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2775 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002776
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002777 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002778
2779 hdev->io_capability = cp->io_capability;
2780
Marcel Holtmann181d6952020-05-06 09:57:47 +02002781 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002783 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002784
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002785 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2786 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002787}
2788
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002789static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790{
2791 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002792 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002794 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002795 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2796 continue;
2797
Johan Hedberge9a416b2011-02-19 12:05:56 -03002798 if (cmd->user_data != conn)
2799 continue;
2800
2801 return cmd;
2802 }
2803
2804 return NULL;
2805}
2806
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002807static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002808{
2809 struct mgmt_rp_pair_device rp;
2810 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002811 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002812
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002813 bacpy(&rp.addr.bdaddr, &conn->dst);
2814 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002815
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002816 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2817 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818
2819 /* So we don't get further callbacks for this connection */
2820 conn->connect_cfm_cb = NULL;
2821 conn->security_cfm_cb = NULL;
2822 conn->disconn_cfm_cb = NULL;
2823
David Herrmann76a68ba2013-04-06 20:28:37 +02002824 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002825
2826 /* The device is paired so there is no need to remove
2827 * its connection parameters anymore.
2828 */
2829 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002830
2831 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002832
2833 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002834}
2835
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002836void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2837{
2838 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002839 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002840
2841 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002842 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002843 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002844 mgmt_pending_remove(cmd);
2845 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002846}
2847
Johan Hedberge9a416b2011-02-19 12:05:56 -03002848static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2849{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002850 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002851
2852 BT_DBG("status %u", status);
2853
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002854 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002855 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002856 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002857 return;
2858 }
2859
2860 cmd->cmd_complete(cmd, mgmt_status(status));
2861 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002862}
2863
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002864static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302865{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002866 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302867
2868 BT_DBG("status %u", status);
2869
2870 if (!status)
2871 return;
2872
2873 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002874 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302875 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002876 return;
2877 }
2878
2879 cmd->cmd_complete(cmd, mgmt_status(status));
2880 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302881}
2882
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002883static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002884 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002885{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002886 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002887 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002888 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002889 u8 sec_level, auth_type;
2890 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002891 int err;
2892
Marcel Holtmann181d6952020-05-06 09:57:47 +02002893 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002894
Szymon Jancf950a30e2013-01-18 12:48:07 +01002895 memset(&rp, 0, sizeof(rp));
2896 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2897 rp.addr.type = cp->addr.type;
2898
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002899 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002900 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2901 MGMT_STATUS_INVALID_PARAMS,
2902 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002903
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002904 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002905 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2906 MGMT_STATUS_INVALID_PARAMS,
2907 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002908
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002909 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002910
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002911 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002912 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2913 MGMT_STATUS_NOT_POWERED, &rp,
2914 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002915 goto unlock;
2916 }
2917
Johan Hedberg55e76b32015-03-10 22:34:40 +02002918 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2919 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2920 MGMT_STATUS_ALREADY_PAIRED, &rp,
2921 sizeof(rp));
2922 goto unlock;
2923 }
2924
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002925 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002926 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002927
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002928 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002929 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2930 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002931 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002932 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002933 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002934
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002935 /* When pairing a new device, it is expected to remember
2936 * this device for future connections. Adding the connection
2937 * parameter information ahead of time allows tracking
2938 * of the slave preferred values and will speed up any
2939 * further connection establishment.
2940 *
2941 * If connection parameters already exist, then they
2942 * will be kept and this function does nothing.
2943 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002944 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2945
2946 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2947 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002948
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002949 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2950 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002951 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002952 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002953
Ville Tervo30e76272011-02-22 16:10:53 -03002954 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002955 int status;
2956
2957 if (PTR_ERR(conn) == -EBUSY)
2958 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002959 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2960 status = MGMT_STATUS_NOT_SUPPORTED;
2961 else if (PTR_ERR(conn) == -ECONNREFUSED)
2962 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002963 else
2964 status = MGMT_STATUS_CONNECT_FAILED;
2965
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002966 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2967 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002968 goto unlock;
2969 }
2970
2971 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002972 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002973 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2974 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002975 goto unlock;
2976 }
2977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002978 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002979 if (!cmd) {
2980 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002981 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002982 goto unlock;
2983 }
2984
Johan Hedberg04ab2742014-12-05 13:36:04 +02002985 cmd->cmd_complete = pairing_complete;
2986
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002987 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002988 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002989 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002990 conn->security_cfm_cb = pairing_complete_cb;
2991 conn->disconn_cfm_cb = pairing_complete_cb;
2992 } else {
2993 conn->connect_cfm_cb = le_pairing_complete_cb;
2994 conn->security_cfm_cb = le_pairing_complete_cb;
2995 conn->disconn_cfm_cb = le_pairing_complete_cb;
2996 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002997
Johan Hedberge9a416b2011-02-19 12:05:56 -03002998 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002999 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003000
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003001 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003002 hci_conn_security(conn, sec_level, auth_type, true)) {
3003 cmd->cmd_complete(cmd, 0);
3004 mgmt_pending_remove(cmd);
3005 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003006
3007 err = 0;
3008
3009unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003010 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003011 return err;
3012}
3013
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3015 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003016{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003017 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003018 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003019 struct hci_conn *conn;
3020 int err;
3021
Marcel Holtmann181d6952020-05-06 09:57:47 +02003022 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003023
Johan Hedberg28424702012-02-02 04:02:29 +02003024 hci_dev_lock(hdev);
3025
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003026 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003027 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3028 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003029 goto unlock;
3030 }
3031
Johan Hedberg333ae952015-03-17 13:48:47 +02003032 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003033 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003034 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3035 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003036 goto unlock;
3037 }
3038
3039 conn = cmd->user_data;
3040
3041 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003042 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3043 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003044 goto unlock;
3045 }
3046
Johan Hedberga511b352014-12-11 21:45:45 +02003047 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3048 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003049
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003050 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3051 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003052unlock:
3053 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003054 return err;
3055}
3056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003057static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003058 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003059 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003060{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003061 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003062 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003063 int err;
3064
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003065 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003066
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003067 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003068 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3069 MGMT_STATUS_NOT_POWERED, addr,
3070 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003071 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003072 }
3073
Johan Hedberg1707c602013-03-15 17:07:15 -05003074 if (addr->type == BDADDR_BREDR)
3075 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003076 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003077 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3078 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003079
Johan Hedberg272d90d2012-02-09 15:26:12 +02003080 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003081 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3082 MGMT_STATUS_NOT_CONNECTED, addr,
3083 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003084 goto done;
3085 }
3086
Johan Hedberg1707c602013-03-15 17:07:15 -05003087 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003088 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003089 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003090 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3091 MGMT_STATUS_SUCCESS, addr,
3092 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003093 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003094 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3095 MGMT_STATUS_FAILED, addr,
3096 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003097
Brian Gix47c15e22011-11-16 13:53:14 -08003098 goto done;
3099 }
3100
Johan Hedberg1707c602013-03-15 17:07:15 -05003101 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003102 if (!cmd) {
3103 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003104 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003105 }
3106
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003107 cmd->cmd_complete = addr_cmd_complete;
3108
Brian Gix0df4c182011-11-16 13:53:13 -08003109 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003110 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3111 struct hci_cp_user_passkey_reply cp;
3112
Johan Hedberg1707c602013-03-15 17:07:15 -05003113 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003114 cp.passkey = passkey;
3115 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3116 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003117 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3118 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003119
Johan Hedberga664b5b2011-02-19 12:06:02 -03003120 if (err < 0)
3121 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003122
Brian Gix0df4c182011-11-16 13:53:13 -08003123done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003124 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003125 return err;
3126}
3127
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303128static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3129 void *data, u16 len)
3130{
3131 struct mgmt_cp_pin_code_neg_reply *cp = data;
3132
Marcel Holtmann181d6952020-05-06 09:57:47 +02003133 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303134
Johan Hedberg1707c602013-03-15 17:07:15 -05003135 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303136 MGMT_OP_PIN_CODE_NEG_REPLY,
3137 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3138}
3139
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3141 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003142{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003143 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003144
Marcel Holtmann181d6952020-05-06 09:57:47 +02003145 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003146
3147 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003148 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3149 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003150
Johan Hedberg1707c602013-03-15 17:07:15 -05003151 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 MGMT_OP_USER_CONFIRM_REPLY,
3153 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003154}
3155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003156static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003158{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003159 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003160
Marcel Holtmann181d6952020-05-06 09:57:47 +02003161 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003162
Johan Hedberg1707c602013-03-15 17:07:15 -05003163 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003164 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3165 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003166}
3167
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003168static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3169 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003170{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003171 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003172
Marcel Holtmann181d6952020-05-06 09:57:47 +02003173 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003174
Johan Hedberg1707c602013-03-15 17:07:15 -05003175 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003176 MGMT_OP_USER_PASSKEY_REPLY,
3177 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003178}
3179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003180static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003182{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003183 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003184
Marcel Holtmann181d6952020-05-06 09:57:47 +02003185 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003186
Johan Hedberg1707c602013-03-15 17:07:15 -05003187 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3189 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003190}
3191
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003192static void adv_expire(struct hci_dev *hdev, u32 flags)
3193{
3194 struct adv_info *adv_instance;
3195 struct hci_request req;
3196 int err;
3197
3198 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3199 if (!adv_instance)
3200 return;
3201
3202 /* stop if current instance doesn't need to be changed */
3203 if (!(adv_instance->flags & flags))
3204 return;
3205
3206 cancel_adv_timeout(hdev);
3207
3208 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3209 if (!adv_instance)
3210 return;
3211
3212 hci_req_init(&req, hdev);
3213 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3214 true);
3215 if (err)
3216 return;
3217
3218 hci_req_run(&req, NULL);
3219}
3220
Marcel Holtmann1904a852015-01-11 13:50:44 -08003221static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003222{
3223 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003224 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003225
Marcel Holtmann181d6952020-05-06 09:57:47 +02003226 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003227
3228 hci_dev_lock(hdev);
3229
Johan Hedberg333ae952015-03-17 13:48:47 +02003230 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003231 if (!cmd)
3232 goto unlock;
3233
3234 cp = cmd->param;
3235
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003236 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003237 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3238 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003239 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003240 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3241 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003242
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003243 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3244 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3245 }
3246
Johan Hedberg13928972013-03-15 17:07:00 -05003247 mgmt_pending_remove(cmd);
3248
3249unlock:
3250 hci_dev_unlock(hdev);
3251}
3252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003253static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003255{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003256 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003257 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003258 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003259 int err;
3260
Marcel Holtmann181d6952020-05-06 09:57:47 +02003261 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003263 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003264
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003265 /* If the old values are the same as the new ones just return a
3266 * direct command complete event.
3267 */
3268 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3269 !memcmp(hdev->short_name, cp->short_name,
3270 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003271 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3272 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003273 goto failed;
3274 }
3275
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003276 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003277
Johan Hedbergb5235a62012-02-21 14:32:24 +02003278 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003279 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003280
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003281 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3282 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003283 if (err < 0)
3284 goto failed;
3285
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003286 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3287 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003288 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003289
Johan Hedbergb5235a62012-02-21 14:32:24 +02003290 goto failed;
3291 }
3292
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003293 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003294 if (!cmd) {
3295 err = -ENOMEM;
3296 goto failed;
3297 }
3298
Johan Hedberg13928972013-03-15 17:07:00 -05003299 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3300
Johan Hedberg890ea892013-03-15 17:06:52 -05003301 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003302
3303 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003304 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003305 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003306 }
3307
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003308 /* The name is stored in the scan response data and so
3309 * no need to udpate the advertising data here.
3310 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003311 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003312 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003313
Johan Hedberg13928972013-03-15 17:07:00 -05003314 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003315 if (err < 0)
3316 mgmt_pending_remove(cmd);
3317
3318failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003319 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003320 return err;
3321}
3322
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003323static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3324 u16 len)
3325{
3326 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003327 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003328 int err;
3329
Marcel Holtmann181d6952020-05-06 09:57:47 +02003330 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003331
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003332 if (!lmp_le_capable(hdev))
3333 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3334 MGMT_STATUS_NOT_SUPPORTED);
3335
Alain Michaud6613bab2020-01-22 19:47:44 +00003336 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003337
3338 hci_dev_lock(hdev);
3339
Alain Michaud6613bab2020-01-22 19:47:44 +00003340 if (hdev->appearance != appearance) {
3341 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003342
3343 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3344 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003345
3346 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003347 }
3348
3349 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3350 0);
3351
3352 hci_dev_unlock(hdev);
3353
3354 return err;
3355}
3356
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303357static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3358 void *data, u16 len)
3359{
3360 struct mgmt_rp_get_phy_confguration rp;
3361
Marcel Holtmann181d6952020-05-06 09:57:47 +02003362 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303363
3364 hci_dev_lock(hdev);
3365
3366 memset(&rp, 0, sizeof(rp));
3367
3368 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3369 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3370 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3371
3372 hci_dev_unlock(hdev);
3373
3374 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3375 &rp, sizeof(rp));
3376}
3377
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303378int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3379{
3380 struct mgmt_ev_phy_configuration_changed ev;
3381
3382 memset(&ev, 0, sizeof(ev));
3383
3384 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3385
3386 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3387 sizeof(ev), skip);
3388}
3389
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303390static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3391 u16 opcode, struct sk_buff *skb)
3392{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303393 struct mgmt_pending_cmd *cmd;
3394
Marcel Holtmann181d6952020-05-06 09:57:47 +02003395 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303396
3397 hci_dev_lock(hdev);
3398
3399 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3400 if (!cmd)
3401 goto unlock;
3402
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303403 if (status) {
3404 mgmt_cmd_status(cmd->sk, hdev->id,
3405 MGMT_OP_SET_PHY_CONFIGURATION,
3406 mgmt_status(status));
3407 } else {
3408 mgmt_cmd_complete(cmd->sk, hdev->id,
3409 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3410 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303411
3412 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303413 }
3414
3415 mgmt_pending_remove(cmd);
3416
3417unlock:
3418 hci_dev_unlock(hdev);
3419}
3420
3421static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3422 void *data, u16 len)
3423{
3424 struct mgmt_cp_set_phy_confguration *cp = data;
3425 struct hci_cp_le_set_default_phy cp_phy;
3426 struct mgmt_pending_cmd *cmd;
3427 struct hci_request req;
3428 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3429 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303430 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303431 int err;
3432
Marcel Holtmann181d6952020-05-06 09:57:47 +02003433 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303434
3435 configurable_phys = get_configurable_phys(hdev);
3436 supported_phys = get_supported_phys(hdev);
3437 selected_phys = __le32_to_cpu(cp->selected_phys);
3438
3439 if (selected_phys & ~supported_phys)
3440 return mgmt_cmd_status(sk, hdev->id,
3441 MGMT_OP_SET_PHY_CONFIGURATION,
3442 MGMT_STATUS_INVALID_PARAMS);
3443
3444 unconfigure_phys = supported_phys & ~configurable_phys;
3445
3446 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3447 return mgmt_cmd_status(sk, hdev->id,
3448 MGMT_OP_SET_PHY_CONFIGURATION,
3449 MGMT_STATUS_INVALID_PARAMS);
3450
3451 if (selected_phys == get_selected_phys(hdev))
3452 return mgmt_cmd_complete(sk, hdev->id,
3453 MGMT_OP_SET_PHY_CONFIGURATION,
3454 0, NULL, 0);
3455
3456 hci_dev_lock(hdev);
3457
3458 if (!hdev_is_powered(hdev)) {
3459 err = mgmt_cmd_status(sk, hdev->id,
3460 MGMT_OP_SET_PHY_CONFIGURATION,
3461 MGMT_STATUS_REJECTED);
3462 goto unlock;
3463 }
3464
3465 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3466 err = mgmt_cmd_status(sk, hdev->id,
3467 MGMT_OP_SET_PHY_CONFIGURATION,
3468 MGMT_STATUS_BUSY);
3469 goto unlock;
3470 }
3471
3472 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3473 pkt_type |= (HCI_DH3 | HCI_DM3);
3474 else
3475 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3476
3477 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3478 pkt_type |= (HCI_DH5 | HCI_DM5);
3479 else
3480 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3481
3482 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3483 pkt_type &= ~HCI_2DH1;
3484 else
3485 pkt_type |= HCI_2DH1;
3486
3487 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3488 pkt_type &= ~HCI_2DH3;
3489 else
3490 pkt_type |= HCI_2DH3;
3491
3492 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3493 pkt_type &= ~HCI_2DH5;
3494 else
3495 pkt_type |= HCI_2DH5;
3496
3497 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3498 pkt_type &= ~HCI_3DH1;
3499 else
3500 pkt_type |= HCI_3DH1;
3501
3502 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3503 pkt_type &= ~HCI_3DH3;
3504 else
3505 pkt_type |= HCI_3DH3;
3506
3507 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3508 pkt_type &= ~HCI_3DH5;
3509 else
3510 pkt_type |= HCI_3DH5;
3511
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303512 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303513 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303514 changed = true;
3515 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303516
3517 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3518 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303519 if (changed)
3520 mgmt_phy_configuration_changed(hdev, sk);
3521
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303522 err = mgmt_cmd_complete(sk, hdev->id,
3523 MGMT_OP_SET_PHY_CONFIGURATION,
3524 0, NULL, 0);
3525
3526 goto unlock;
3527 }
3528
3529 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3530 len);
3531 if (!cmd) {
3532 err = -ENOMEM;
3533 goto unlock;
3534 }
3535
3536 hci_req_init(&req, hdev);
3537
3538 memset(&cp_phy, 0, sizeof(cp_phy));
3539
3540 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3541 cp_phy.all_phys |= 0x01;
3542
3543 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3544 cp_phy.all_phys |= 0x02;
3545
3546 if (selected_phys & MGMT_PHY_LE_1M_TX)
3547 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3548
3549 if (selected_phys & MGMT_PHY_LE_2M_TX)
3550 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3551
3552 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3553 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3554
3555 if (selected_phys & MGMT_PHY_LE_1M_RX)
3556 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3557
3558 if (selected_phys & MGMT_PHY_LE_2M_RX)
3559 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3560
3561 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3562 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3563
3564 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3565
3566 err = hci_req_run_skb(&req, set_default_phy_complete);
3567 if (err < 0)
3568 mgmt_pending_remove(cmd);
3569
3570unlock:
3571 hci_dev_unlock(hdev);
3572
3573 return err;
3574}
3575
Alain Michaud600a8742020-01-07 00:43:17 +00003576static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3577 u16 len)
3578{
3579 int err = MGMT_STATUS_SUCCESS;
3580 struct mgmt_cp_set_blocked_keys *keys = data;
3581 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3582 sizeof(struct mgmt_blocked_key_info));
3583 u16 key_count, expected_len;
3584 int i;
3585
Marcel Holtmann181d6952020-05-06 09:57:47 +02003586 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003587
3588 key_count = __le16_to_cpu(keys->key_count);
3589 if (key_count > max_key_count) {
3590 bt_dev_err(hdev, "too big key_count value %u", key_count);
3591 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3592 MGMT_STATUS_INVALID_PARAMS);
3593 }
3594
3595 expected_len = struct_size(keys, keys, key_count);
3596 if (expected_len != len) {
3597 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3598 expected_len, len);
3599 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3600 MGMT_STATUS_INVALID_PARAMS);
3601 }
3602
3603 hci_dev_lock(hdev);
3604
3605 hci_blocked_keys_clear(hdev);
3606
3607 for (i = 0; i < keys->key_count; ++i) {
3608 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3609
3610 if (!b) {
3611 err = MGMT_STATUS_NO_RESOURCES;
3612 break;
3613 }
3614
3615 b->type = keys->keys[i].type;
3616 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3617 list_add_rcu(&b->list, &hdev->blocked_keys);
3618 }
3619 hci_dev_unlock(hdev);
3620
3621 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3622 err, NULL, 0);
3623}
3624
Alain Michaud00bce3f2020-03-05 16:14:59 +00003625static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3626 void *data, u16 len)
3627{
3628 struct mgmt_mode *cp = data;
3629 int err;
3630 bool changed = false;
3631
Marcel Holtmann181d6952020-05-06 09:57:47 +02003632 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003633
3634 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3635 return mgmt_cmd_status(sk, hdev->id,
3636 MGMT_OP_SET_WIDEBAND_SPEECH,
3637 MGMT_STATUS_NOT_SUPPORTED);
3638
3639 if (cp->val != 0x00 && cp->val != 0x01)
3640 return mgmt_cmd_status(sk, hdev->id,
3641 MGMT_OP_SET_WIDEBAND_SPEECH,
3642 MGMT_STATUS_INVALID_PARAMS);
3643
3644 hci_dev_lock(hdev);
3645
3646 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3647 err = mgmt_cmd_status(sk, hdev->id,
3648 MGMT_OP_SET_WIDEBAND_SPEECH,
3649 MGMT_STATUS_BUSY);
3650 goto unlock;
3651 }
3652
3653 if (hdev_is_powered(hdev) &&
3654 !!cp->val != hci_dev_test_flag(hdev,
3655 HCI_WIDEBAND_SPEECH_ENABLED)) {
3656 err = mgmt_cmd_status(sk, hdev->id,
3657 MGMT_OP_SET_WIDEBAND_SPEECH,
3658 MGMT_STATUS_REJECTED);
3659 goto unlock;
3660 }
3661
3662 if (cp->val)
3663 changed = !hci_dev_test_and_set_flag(hdev,
3664 HCI_WIDEBAND_SPEECH_ENABLED);
3665 else
3666 changed = hci_dev_test_and_clear_flag(hdev,
3667 HCI_WIDEBAND_SPEECH_ENABLED);
3668
3669 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3670 if (err < 0)
3671 goto unlock;
3672
3673 if (changed)
3674 err = new_settings(hdev, sk);
3675
3676unlock:
3677 hci_dev_unlock(hdev);
3678 return err;
3679}
3680
Marcel Holtmannbc292252020-04-03 21:44:05 +02003681static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3682 void *data, u16 data_len)
3683{
3684 char buf[16];
3685 struct mgmt_rp_read_security_info *rp = (void *)buf;
3686 u16 sec_len = 0;
3687 u8 flags = 0;
3688
3689 bt_dev_dbg(hdev, "sock %p", sk);
3690
3691 memset(&buf, 0, sizeof(buf));
3692
3693 hci_dev_lock(hdev);
3694
3695 /* When the Read Simple Pairing Options command is supported, then
3696 * the remote public key validation is supported.
3697 */
3698 if (hdev->commands[41] & 0x08)
3699 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3700
3701 flags |= 0x02; /* Remote public key validation (LE) */
3702
3703 /* When the Read Encryption Key Size command is supported, then the
3704 * encryption key size is enforced.
3705 */
3706 if (hdev->commands[20] & 0x10)
3707 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3708
3709 flags |= 0x08; /* Encryption key size enforcement (LE) */
3710
3711 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3712
3713 /* When the Read Simple Pairing Options command is supported, then
3714 * also max encryption key size information is provided.
3715 */
3716 if (hdev->commands[41] & 0x08)
3717 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3718 hdev->max_enc_key_size);
3719
3720 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3721
3722 rp->sec_len = cpu_to_le16(sec_len);
3723
3724 hci_dev_unlock(hdev);
3725
3726 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3727 rp, sizeof(*rp) + sec_len);
3728}
3729
Marcel Holtmanne625e502020-05-06 09:57:52 +02003730#ifdef CONFIG_BT_FEATURE_DEBUG
3731/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3732static const u8 debug_uuid[16] = {
3733 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3734 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3735};
3736#endif
3737
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003738static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3739 void *data, u16 data_len)
3740{
3741 char buf[42];
3742 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3743 u16 idx = 0;
3744
3745 bt_dev_dbg(hdev, "sock %p", sk);
3746
3747 memset(&buf, 0, sizeof(buf));
3748
Marcel Holtmanne625e502020-05-06 09:57:52 +02003749#ifdef CONFIG_BT_FEATURE_DEBUG
3750 if (!hdev) {
3751 u32 flags = bt_dbg_get() ? BIT(0) : 0;
3752
3753 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3754 rp->features[idx].flags = cpu_to_le32(flags);
3755 idx++;
3756 }
3757#endif
3758
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003759 rp->feature_count = cpu_to_le16(idx);
3760
3761 /* After reading the experimental features information, enable
3762 * the events to update client on any future change.
3763 */
3764 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3765
3766 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3767 MGMT_OP_READ_EXP_FEATURES_INFO,
3768 0, rp, sizeof(*rp) + (20 * idx));
3769}
3770
Marcel Holtmanne625e502020-05-06 09:57:52 +02003771#ifdef CONFIG_BT_FEATURE_DEBUG
3772static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3773{
3774 struct mgmt_ev_exp_feature_changed ev;
3775
3776 memset(&ev, 0, sizeof(ev));
3777 memcpy(ev.uuid, debug_uuid, 16);
3778 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3779
3780 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3781 &ev, sizeof(ev),
3782 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3783}
3784#endif
3785
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003786static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3787 void *data, u16 data_len)
3788{
3789 struct mgmt_cp_set_exp_feature *cp = data;
3790 struct mgmt_rp_set_exp_feature rp;
3791
3792 bt_dev_dbg(hdev, "sock %p", sk);
3793
3794 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3795 memset(rp.uuid, 0, 16);
3796 rp.flags = cpu_to_le32(0);
3797
Marcel Holtmanne625e502020-05-06 09:57:52 +02003798#ifdef CONFIG_BT_FEATURE_DEBUG
3799 if (!hdev) {
3800 bool changed = bt_dbg_get();
3801
3802 bt_dbg_set(false);
3803
3804 if (changed)
3805 exp_debug_feature_changed(false, sk);
3806 }
3807#endif
3808
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003809 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3810
3811 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3812 MGMT_OP_SET_EXP_FEATURE, 0,
3813 &rp, sizeof(rp));
3814 }
3815
Marcel Holtmanne625e502020-05-06 09:57:52 +02003816#ifdef CONFIG_BT_FEATURE_DEBUG
3817 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3818 bool val, changed;
3819 int err;
3820
3821 /* Command requires to use the non-controller index */
3822 if (hdev)
3823 return mgmt_cmd_status(sk, hdev->id,
3824 MGMT_OP_SET_EXP_FEATURE,
3825 MGMT_STATUS_INVALID_INDEX);
3826
3827 /* Parameters are limited to a single octet */
3828 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3829 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3830 MGMT_OP_SET_EXP_FEATURE,
3831 MGMT_STATUS_INVALID_PARAMS);
3832
3833 /* Only boolean on/off is supported */
3834 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3835 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3836 MGMT_OP_SET_EXP_FEATURE,
3837 MGMT_STATUS_INVALID_PARAMS);
3838
3839 val = !!cp->param[0];
3840 changed = val ? !bt_dbg_get() : bt_dbg_get();
3841 bt_dbg_set(val);
3842
3843 memcpy(rp.uuid, debug_uuid, 16);
3844 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3845
3846 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3847
3848 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3849 MGMT_OP_SET_EXP_FEATURE, 0,
3850 &rp, sizeof(rp));
3851
3852 if (changed)
3853 exp_debug_feature_changed(val, sk);
3854
3855 return err;
3856 }
3857#endif
3858
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003859 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3860 MGMT_OP_SET_EXP_FEATURE,
3861 MGMT_STATUS_NOT_SUPPORTED);
3862}
3863
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003864#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
3865
3866static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3867 u16 data_len)
3868{
3869 struct mgmt_cp_get_device_flags *cp = data;
3870 struct mgmt_rp_get_device_flags rp;
3871 struct bdaddr_list_with_flags *br_params;
3872 struct hci_conn_params *params;
3873 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3874 u32 current_flags = 0;
3875 u8 status = MGMT_STATUS_INVALID_PARAMS;
3876
3877 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
3878 &cp->addr.bdaddr, cp->addr.type);
3879
3880 if (cp->addr.type == BDADDR_BREDR) {
3881 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3882 &cp->addr.bdaddr,
3883 cp->addr.type);
3884 if (!br_params)
3885 goto done;
3886
3887 current_flags = br_params->current_flags;
3888 } else {
3889 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
3890 le_addr_type(cp->addr.type));
3891
3892 if (!params)
3893 goto done;
3894
3895 current_flags = params->current_flags;
3896 }
3897
3898 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3899 rp.addr.type = cp->addr.type;
3900 rp.supported_flags = cpu_to_le32(supported_flags);
3901 rp.current_flags = cpu_to_le32(current_flags);
3902
3903 status = MGMT_STATUS_SUCCESS;
3904
3905done:
3906 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
3907 &rp, sizeof(rp));
3908}
3909
3910static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
3911 bdaddr_t *bdaddr, u8 bdaddr_type,
3912 u32 supported_flags, u32 current_flags)
3913{
3914 struct mgmt_ev_device_flags_changed ev;
3915
3916 bacpy(&ev.addr.bdaddr, bdaddr);
3917 ev.addr.type = bdaddr_type;
3918 ev.supported_flags = cpu_to_le32(supported_flags);
3919 ev.current_flags = cpu_to_le32(current_flags);
3920
3921 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
3922}
3923
3924static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3925 u16 len)
3926{
3927 struct mgmt_cp_set_device_flags *cp = data;
3928 struct bdaddr_list_with_flags *br_params;
3929 struct hci_conn_params *params;
3930 u8 status = MGMT_STATUS_INVALID_PARAMS;
3931 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3932 u32 current_flags = __le32_to_cpu(cp->current_flags);
3933
3934 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
3935 &cp->addr.bdaddr, cp->addr.type,
3936 __le32_to_cpu(current_flags));
3937
3938 if ((supported_flags | current_flags) != supported_flags) {
3939 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
3940 current_flags, supported_flags);
3941 goto done;
3942 }
3943
3944 if (cp->addr.type == BDADDR_BREDR) {
3945 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3946 &cp->addr.bdaddr,
3947 cp->addr.type);
3948
3949 if (br_params) {
3950 br_params->current_flags = current_flags;
3951 status = MGMT_STATUS_SUCCESS;
3952 } else {
3953 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
3954 &cp->addr.bdaddr, cp->addr.type);
3955 }
3956 } else {
3957 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
3958 le_addr_type(cp->addr.type));
3959 if (params) {
3960 params->current_flags = current_flags;
3961 status = MGMT_STATUS_SUCCESS;
3962 } else {
3963 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
3964 &cp->addr.bdaddr,
3965 le_addr_type(cp->addr.type));
3966 }
3967 }
3968
3969done:
3970 if (status == MGMT_STATUS_SUCCESS)
3971 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
3972 supported_flags, current_flags);
3973
3974 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
3975 &cp->addr, sizeof(cp->addr));
3976}
3977
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02003978static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
3979 void *data, u16 len)
3980{
3981 struct adv_monitor *monitor = NULL;
3982 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
3983 int handle;
3984 size_t rp_size = 0;
3985 __u32 supported = 0;
3986 __u16 num_handles = 0;
3987 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
3988
3989 BT_DBG("request for %s", hdev->name);
3990
3991 hci_dev_lock(hdev);
3992
3993 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
3994 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
3995
3996 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
3997 handles[num_handles++] = monitor->handle;
3998 }
3999
4000 hci_dev_unlock(hdev);
4001
4002 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4003 rp = kmalloc(rp_size, GFP_KERNEL);
4004 if (!rp)
4005 return -ENOMEM;
4006
4007 /* Once controller-based monitoring is in place, the enabled_features
4008 * should reflect the use.
4009 */
4010 rp->supported_features = cpu_to_le32(supported);
4011 rp->enabled_features = 0;
4012 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4013 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4014 rp->num_handles = cpu_to_le16(num_handles);
4015 if (num_handles)
4016 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4017
4018 return mgmt_cmd_complete(sk, hdev->id,
4019 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4020 MGMT_STATUS_SUCCESS, rp, rp_size);
4021}
4022
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004023static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4024 u16 opcode, struct sk_buff *skb)
4025{
4026 struct mgmt_rp_read_local_oob_data mgmt_rp;
4027 size_t rp_size = sizeof(mgmt_rp);
4028 struct mgmt_pending_cmd *cmd;
4029
Marcel Holtmann181d6952020-05-06 09:57:47 +02004030 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004031
4032 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4033 if (!cmd)
4034 return;
4035
4036 if (status || !skb) {
4037 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4038 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4039 goto remove;
4040 }
4041
4042 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4043
4044 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4045 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4046
4047 if (skb->len < sizeof(*rp)) {
4048 mgmt_cmd_status(cmd->sk, hdev->id,
4049 MGMT_OP_READ_LOCAL_OOB_DATA,
4050 MGMT_STATUS_FAILED);
4051 goto remove;
4052 }
4053
4054 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4055 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4056
4057 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4058 } else {
4059 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4060
4061 if (skb->len < sizeof(*rp)) {
4062 mgmt_cmd_status(cmd->sk, hdev->id,
4063 MGMT_OP_READ_LOCAL_OOB_DATA,
4064 MGMT_STATUS_FAILED);
4065 goto remove;
4066 }
4067
4068 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4069 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4070
4071 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4072 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4073 }
4074
4075 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4076 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4077
4078remove:
4079 mgmt_pending_remove(cmd);
4080}
4081
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004082static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004083 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004084{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004085 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004086 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004087 int err;
4088
Marcel Holtmann181d6952020-05-06 09:57:47 +02004089 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004090
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004091 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004092
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004093 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004094 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4095 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004096 goto unlock;
4097 }
4098
Andre Guedes9a1a1992012-07-24 15:03:48 -03004099 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004100 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4101 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004102 goto unlock;
4103 }
4104
Johan Hedberg333ae952015-03-17 13:48:47 +02004105 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004106 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4107 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004108 goto unlock;
4109 }
4110
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004111 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004112 if (!cmd) {
4113 err = -ENOMEM;
4114 goto unlock;
4115 }
4116
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004117 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004118
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004119 if (bredr_sc_enabled(hdev))
4120 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4121 else
4122 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4123
4124 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004125 if (err < 0)
4126 mgmt_pending_remove(cmd);
4127
4128unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004129 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004130 return err;
4131}
4132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004133static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004134 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004135{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004136 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004137 int err;
4138
Marcel Holtmann181d6952020-05-06 09:57:47 +02004139 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004140
Johan Hedberg5d57e792015-01-23 10:10:38 +02004141 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004142 return mgmt_cmd_complete(sk, hdev->id,
4143 MGMT_OP_ADD_REMOTE_OOB_DATA,
4144 MGMT_STATUS_INVALID_PARAMS,
4145 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004147 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004148
Marcel Holtmannec109112014-01-10 02:07:30 -08004149 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4150 struct mgmt_cp_add_remote_oob_data *cp = data;
4151 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004152
Johan Hedbergc19a4952014-11-17 20:52:19 +02004153 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004154 err = mgmt_cmd_complete(sk, hdev->id,
4155 MGMT_OP_ADD_REMOTE_OOB_DATA,
4156 MGMT_STATUS_INVALID_PARAMS,
4157 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004158 goto unlock;
4159 }
4160
Marcel Holtmannec109112014-01-10 02:07:30 -08004161 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004162 cp->addr.type, cp->hash,
4163 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004164 if (err < 0)
4165 status = MGMT_STATUS_FAILED;
4166 else
4167 status = MGMT_STATUS_SUCCESS;
4168
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004169 err = mgmt_cmd_complete(sk, hdev->id,
4170 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4171 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004172 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4173 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004174 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004175 u8 status;
4176
Johan Hedberg86df9202014-10-26 20:52:27 +01004177 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004178 /* Enforce zero-valued 192-bit parameters as
4179 * long as legacy SMP OOB isn't implemented.
4180 */
4181 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4182 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004183 err = mgmt_cmd_complete(sk, hdev->id,
4184 MGMT_OP_ADD_REMOTE_OOB_DATA,
4185 MGMT_STATUS_INVALID_PARAMS,
4186 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004187 goto unlock;
4188 }
4189
Johan Hedberg86df9202014-10-26 20:52:27 +01004190 rand192 = NULL;
4191 hash192 = NULL;
4192 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004193 /* In case one of the P-192 values is set to zero,
4194 * then just disable OOB data for P-192.
4195 */
4196 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4197 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4198 rand192 = NULL;
4199 hash192 = NULL;
4200 } else {
4201 rand192 = cp->rand192;
4202 hash192 = cp->hash192;
4203 }
4204 }
4205
4206 /* In case one of the P-256 values is set to zero, then just
4207 * disable OOB data for P-256.
4208 */
4209 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4210 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4211 rand256 = NULL;
4212 hash256 = NULL;
4213 } else {
4214 rand256 = cp->rand256;
4215 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004216 }
4217
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004218 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004219 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004220 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004221 if (err < 0)
4222 status = MGMT_STATUS_FAILED;
4223 else
4224 status = MGMT_STATUS_SUCCESS;
4225
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004226 err = mgmt_cmd_complete(sk, hdev->id,
4227 MGMT_OP_ADD_REMOTE_OOB_DATA,
4228 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004229 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004230 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4231 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4233 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004234 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004235
Johan Hedbergc19a4952014-11-17 20:52:19 +02004236unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004237 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004238 return err;
4239}
4240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004241static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004242 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004244 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004245 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004246 int err;
4247
Marcel Holtmann181d6952020-05-06 09:57:47 +02004248 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004249
Johan Hedbergc19a4952014-11-17 20:52:19 +02004250 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004251 return mgmt_cmd_complete(sk, hdev->id,
4252 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4253 MGMT_STATUS_INVALID_PARAMS,
4254 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004255
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004256 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004257
Johan Hedbergeedbd582014-11-15 09:34:23 +02004258 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4259 hci_remote_oob_data_clear(hdev);
4260 status = MGMT_STATUS_SUCCESS;
4261 goto done;
4262 }
4263
Johan Hedberg6928a922014-10-26 20:46:09 +01004264 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004265 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004266 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004267 else
Szymon Janca6785be2012-12-13 15:11:21 +01004268 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004269
Johan Hedbergeedbd582014-11-15 09:34:23 +02004270done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004271 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4272 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004273
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004274 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004275 return err;
4276}
4277
Johan Hedberge68f0722015-11-11 08:30:30 +02004278void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004279{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004280 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004281
Marcel Holtmann181d6952020-05-06 09:57:47 +02004282 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004283
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004284 hci_dev_lock(hdev);
4285
Johan Hedberg333ae952015-03-17 13:48:47 +02004286 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004287 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004288 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004289
Johan Hedberg78b781c2016-01-05 13:19:32 +02004290 if (!cmd)
4291 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4292
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004293 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004294 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004295 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004296 }
4297
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004298 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004299
4300 /* Handle suspend notifier */
4301 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4302 hdev->suspend_tasks)) {
4303 bt_dev_dbg(hdev, "Unpaused discovery");
4304 wake_up(&hdev->suspend_wait_q);
4305 }
Andre Guedes7c307722013-04-30 15:29:28 -03004306}
4307
Johan Hedberg591752a2015-11-11 08:11:24 +02004308static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4309 uint8_t *mgmt_status)
4310{
4311 switch (type) {
4312 case DISCOV_TYPE_LE:
4313 *mgmt_status = mgmt_le_support(hdev);
4314 if (*mgmt_status)
4315 return false;
4316 break;
4317 case DISCOV_TYPE_INTERLEAVED:
4318 *mgmt_status = mgmt_le_support(hdev);
4319 if (*mgmt_status)
4320 return false;
4321 /* Intentional fall-through */
4322 case DISCOV_TYPE_BREDR:
4323 *mgmt_status = mgmt_bredr_support(hdev);
4324 if (*mgmt_status)
4325 return false;
4326 break;
4327 default:
4328 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4329 return false;
4330 }
4331
4332 return true;
4333}
4334
Johan Hedberg78b781c2016-01-05 13:19:32 +02004335static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4336 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004337{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004338 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004339 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004340 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004341 int err;
4342
Marcel Holtmann181d6952020-05-06 09:57:47 +02004343 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004345 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004346
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004347 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004348 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004349 MGMT_STATUS_NOT_POWERED,
4350 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004351 goto failed;
4352 }
4353
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004354 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004355 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004356 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4357 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004358 goto failed;
4359 }
4360
Johan Hedberg591752a2015-11-11 08:11:24 +02004361 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004362 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4363 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004364 goto failed;
4365 }
4366
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004367 /* Can't start discovery when it is paused */
4368 if (hdev->discovery_paused) {
4369 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4370 &cp->type, sizeof(cp->type));
4371 goto failed;
4372 }
4373
Marcel Holtmann22078802014-12-05 11:45:22 +01004374 /* Clear the discovery filter first to free any previously
4375 * allocated memory for the UUID list.
4376 */
4377 hci_discovery_filter_clear(hdev);
4378
Andre Guedes4aab14e2012-02-17 20:39:36 -03004379 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004380 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004381 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4382 hdev->discovery.limited = true;
4383 else
4384 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004385
Johan Hedberg78b781c2016-01-05 13:19:32 +02004386 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004387 if (!cmd) {
4388 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004389 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004390 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004391
Johan Hedberge68f0722015-11-11 08:30:30 +02004392 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004393
4394 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004395 queue_work(hdev->req_workqueue, &hdev->discov_update);
4396 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004397
4398failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004399 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004400 return err;
4401}
4402
Johan Hedberg78b781c2016-01-05 13:19:32 +02004403static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4404 void *data, u16 len)
4405{
4406 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4407 data, len);
4408}
4409
4410static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4411 void *data, u16 len)
4412{
4413 return start_discovery_internal(sk, hdev,
4414 MGMT_OP_START_LIMITED_DISCOVERY,
4415 data, len);
4416}
4417
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004418static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4419 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004420{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004421 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4422 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004423}
4424
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004425static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4426 void *data, u16 len)
4427{
4428 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004429 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004430 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4431 u16 uuid_count, expected_len;
4432 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004433 int err;
4434
Marcel Holtmann181d6952020-05-06 09:57:47 +02004435 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004436
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004437 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004438
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004439 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004440 err = mgmt_cmd_complete(sk, hdev->id,
4441 MGMT_OP_START_SERVICE_DISCOVERY,
4442 MGMT_STATUS_NOT_POWERED,
4443 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004444 goto failed;
4445 }
4446
4447 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004448 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004449 err = mgmt_cmd_complete(sk, hdev->id,
4450 MGMT_OP_START_SERVICE_DISCOVERY,
4451 MGMT_STATUS_BUSY, &cp->type,
4452 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004453 goto failed;
4454 }
4455
4456 uuid_count = __le16_to_cpu(cp->uuid_count);
4457 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004458 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4459 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004460 err = mgmt_cmd_complete(sk, hdev->id,
4461 MGMT_OP_START_SERVICE_DISCOVERY,
4462 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4463 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004464 goto failed;
4465 }
4466
4467 expected_len = sizeof(*cp) + uuid_count * 16;
4468 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004469 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4470 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004471 err = mgmt_cmd_complete(sk, hdev->id,
4472 MGMT_OP_START_SERVICE_DISCOVERY,
4473 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4474 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004475 goto failed;
4476 }
4477
Johan Hedberg591752a2015-11-11 08:11:24 +02004478 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4479 err = mgmt_cmd_complete(sk, hdev->id,
4480 MGMT_OP_START_SERVICE_DISCOVERY,
4481 status, &cp->type, sizeof(cp->type));
4482 goto failed;
4483 }
4484
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004485 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004486 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004487 if (!cmd) {
4488 err = -ENOMEM;
4489 goto failed;
4490 }
4491
Johan Hedberg2922a942014-12-05 13:36:06 +02004492 cmd->cmd_complete = service_discovery_cmd_complete;
4493
Marcel Holtmann22078802014-12-05 11:45:22 +01004494 /* Clear the discovery filter first to free any previously
4495 * allocated memory for the UUID list.
4496 */
4497 hci_discovery_filter_clear(hdev);
4498
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004499 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004500 hdev->discovery.type = cp->type;
4501 hdev->discovery.rssi = cp->rssi;
4502 hdev->discovery.uuid_count = uuid_count;
4503
4504 if (uuid_count > 0) {
4505 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4506 GFP_KERNEL);
4507 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004508 err = mgmt_cmd_complete(sk, hdev->id,
4509 MGMT_OP_START_SERVICE_DISCOVERY,
4510 MGMT_STATUS_FAILED,
4511 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004512 mgmt_pending_remove(cmd);
4513 goto failed;
4514 }
4515 }
4516
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004517 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004518 queue_work(hdev->req_workqueue, &hdev->discov_update);
4519 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004520
4521failed:
4522 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004523 return err;
4524}
4525
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004526void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004527{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004528 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004529
Marcel Holtmann181d6952020-05-06 09:57:47 +02004530 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004531
4532 hci_dev_lock(hdev);
4533
Johan Hedberg333ae952015-03-17 13:48:47 +02004534 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004535 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004536 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004537 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004538 }
4539
Andre Guedes0e05bba2013-04-30 15:29:33 -03004540 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004541
4542 /* Handle suspend notifier */
4543 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4544 bt_dev_dbg(hdev, "Paused discovery");
4545 wake_up(&hdev->suspend_wait_q);
4546 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004547}
4548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004549static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004550 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004551{
Johan Hedbergd9306502012-02-20 23:25:18 +02004552 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004553 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004554 int err;
4555
Marcel Holtmann181d6952020-05-06 09:57:47 +02004556 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004557
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004558 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004559
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004560 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004561 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4562 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4563 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004564 goto unlock;
4565 }
4566
4567 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4569 MGMT_STATUS_INVALID_PARAMS,
4570 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004571 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004572 }
4573
Johan Hedberg2922a942014-12-05 13:36:06 +02004574 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004575 if (!cmd) {
4576 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004577 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004578 }
4579
Johan Hedberg2922a942014-12-05 13:36:06 +02004580 cmd->cmd_complete = generic_cmd_complete;
4581
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004582 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4583 queue_work(hdev->req_workqueue, &hdev->discov_update);
4584 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004585
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004586unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004587 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004588 return err;
4589}
4590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004591static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004592 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004593{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004594 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004595 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004596 int err;
4597
Marcel Holtmann181d6952020-05-06 09:57:47 +02004598 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004599
Johan Hedberg561aafb2012-01-04 13:31:59 +02004600 hci_dev_lock(hdev);
4601
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004602 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004603 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4604 MGMT_STATUS_FAILED, &cp->addr,
4605 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004606 goto failed;
4607 }
4608
Johan Hedberga198e7b2012-02-17 14:27:06 +02004609 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004610 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004611 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4612 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4613 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004614 goto failed;
4615 }
4616
4617 if (cp->name_known) {
4618 e->name_state = NAME_KNOWN;
4619 list_del(&e->list);
4620 } else {
4621 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004622 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004623 }
4624
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004625 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4626 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004627
4628failed:
4629 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004630 return err;
4631}
4632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004633static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004634 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004635{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004636 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004637 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004638 int err;
4639
Marcel Holtmann181d6952020-05-06 09:57:47 +02004640 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004641
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004642 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004643 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4644 MGMT_STATUS_INVALID_PARAMS,
4645 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004646
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004647 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004648
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004649 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4650 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004651 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004652 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004653 goto done;
4654 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004655
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004656 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4657 sk);
4658 status = MGMT_STATUS_SUCCESS;
4659
4660done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004661 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4662 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004664 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004665
4666 return err;
4667}
4668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004669static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004670 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004671{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004672 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004673 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004674 int err;
4675
Marcel Holtmann181d6952020-05-06 09:57:47 +02004676 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004677
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004678 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004679 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4680 MGMT_STATUS_INVALID_PARAMS,
4681 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004683 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004684
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004685 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4686 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004687 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004688 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004689 goto done;
4690 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004691
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004692 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4693 sk);
4694 status = MGMT_STATUS_SUCCESS;
4695
4696done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004697 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4698 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004700 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004701
4702 return err;
4703}
4704
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004705static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4706 u16 len)
4707{
4708 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004709 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004710 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004711 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004712
Marcel Holtmann181d6952020-05-06 09:57:47 +02004713 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004714
Szymon Jancc72d4b82012-03-16 16:02:57 +01004715 source = __le16_to_cpu(cp->source);
4716
4717 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004718 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4719 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004720
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004721 hci_dev_lock(hdev);
4722
Szymon Jancc72d4b82012-03-16 16:02:57 +01004723 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004724 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4725 hdev->devid_product = __le16_to_cpu(cp->product);
4726 hdev->devid_version = __le16_to_cpu(cp->version);
4727
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004728 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4729 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004730
Johan Hedberg890ea892013-03-15 17:06:52 -05004731 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004732 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004733 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004734
4735 hci_dev_unlock(hdev);
4736
4737 return err;
4738}
4739
Arman Uguray24b4f382015-03-23 15:57:12 -07004740static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4741 u16 opcode)
4742{
Marcel Holtmann181d6952020-05-06 09:57:47 +02004743 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07004744}
4745
Marcel Holtmann1904a852015-01-11 13:50:44 -08004746static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4747 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004748{
4749 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004750 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004751 u8 instance;
4752 struct adv_info *adv_instance;
4753 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004754
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304755 hci_dev_lock(hdev);
4756
Johan Hedberg4375f102013-09-25 13:26:10 +03004757 if (status) {
4758 u8 mgmt_err = mgmt_status(status);
4759
4760 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4761 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304762 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004763 }
4764
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004765 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004766 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004767 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004768 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004769
Johan Hedberg4375f102013-09-25 13:26:10 +03004770 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4771 &match);
4772
4773 new_settings(hdev, match.sk);
4774
4775 if (match.sk)
4776 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304777
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004778 /* Handle suspend notifier */
4779 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
4780 hdev->suspend_tasks)) {
4781 bt_dev_dbg(hdev, "Paused advertising");
4782 wake_up(&hdev->suspend_wait_q);
4783 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
4784 hdev->suspend_tasks)) {
4785 bt_dev_dbg(hdev, "Unpaused advertising");
4786 wake_up(&hdev->suspend_wait_q);
4787 }
4788
Arman Uguray24b4f382015-03-23 15:57:12 -07004789 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004790 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004791 */
4792 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004793 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004794 goto unlock;
4795
Florian Grandel7816b822015-06-18 03:16:45 +02004796 instance = hdev->cur_adv_instance;
4797 if (!instance) {
4798 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4799 struct adv_info, list);
4800 if (!adv_instance)
4801 goto unlock;
4802
4803 instance = adv_instance->instance;
4804 }
4805
Arman Uguray24b4f382015-03-23 15:57:12 -07004806 hci_req_init(&req, hdev);
4807
Johan Hedbergf2252572015-11-18 12:49:20 +02004808 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004809
Florian Grandel7816b822015-06-18 03:16:45 +02004810 if (!err)
4811 err = hci_req_run(&req, enable_advertising_instance);
4812
4813 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004814 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004815
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304816unlock:
4817 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004818}
4819
Marcel Holtmann21b51872013-10-10 09:47:53 -07004820static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4821 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004822{
4823 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004824 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004825 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004826 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004827 int err;
4828
Marcel Holtmann181d6952020-05-06 09:57:47 +02004829 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03004830
Johan Hedberge6fe7982013-10-02 15:45:22 +03004831 status = mgmt_le_support(hdev);
4832 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004833 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4834 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004835
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004836 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004837 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4838 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004839
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004840 if (hdev->advertising_paused)
4841 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4842 MGMT_STATUS_BUSY);
4843
Johan Hedberg4375f102013-09-25 13:26:10 +03004844 hci_dev_lock(hdev);
4845
4846 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004847
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004848 /* The following conditions are ones which mean that we should
4849 * not do any HCI communication but directly send a mgmt
4850 * response to user space (after toggling the flag if
4851 * necessary).
4852 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004853 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004854 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4855 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004856 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004857 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004858 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004859 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004860
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004861 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004862 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004863 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004864 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004865 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004866 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004867 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004868 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004869 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004870 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004871 }
4872
4873 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4874 if (err < 0)
4875 goto unlock;
4876
4877 if (changed)
4878 err = new_settings(hdev, sk);
4879
4880 goto unlock;
4881 }
4882
Johan Hedberg333ae952015-03-17 13:48:47 +02004883 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4884 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004885 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4886 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004887 goto unlock;
4888 }
4889
4890 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4891 if (!cmd) {
4892 err = -ENOMEM;
4893 goto unlock;
4894 }
4895
4896 hci_req_init(&req, hdev);
4897
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004898 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004899 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004900 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004901 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004902
Florian Grandel7816b822015-06-18 03:16:45 +02004903 cancel_adv_timeout(hdev);
4904
Arman Uguray24b4f382015-03-23 15:57:12 -07004905 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004906 /* Switch to instance "0" for the Set Advertising setting.
4907 * We cannot use update_[adv|scan_rsp]_data() here as the
4908 * HCI_ADVERTISING flag is not yet set.
4909 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004910 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304911
4912 if (ext_adv_capable(hdev)) {
4913 __hci_req_start_ext_adv(&req, 0x00);
4914 } else {
4915 __hci_req_update_adv_data(&req, 0x00);
4916 __hci_req_update_scan_rsp_data(&req, 0x00);
4917 __hci_req_enable_advertising(&req);
4918 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004919 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004920 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004921 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004922
4923 err = hci_req_run(&req, set_advertising_complete);
4924 if (err < 0)
4925 mgmt_pending_remove(cmd);
4926
4927unlock:
4928 hci_dev_unlock(hdev);
4929 return err;
4930}
4931
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004932static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4933 void *data, u16 len)
4934{
4935 struct mgmt_cp_set_static_address *cp = data;
4936 int err;
4937
Marcel Holtmann181d6952020-05-06 09:57:47 +02004938 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004939
Marcel Holtmann62af4442013-10-02 22:10:32 -07004940 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004941 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4942 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004943
4944 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004945 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4946 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004947
4948 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4949 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004950 return mgmt_cmd_status(sk, hdev->id,
4951 MGMT_OP_SET_STATIC_ADDRESS,
4952 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004953
4954 /* Two most significant bits shall be set */
4955 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004956 return mgmt_cmd_status(sk, hdev->id,
4957 MGMT_OP_SET_STATIC_ADDRESS,
4958 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004959 }
4960
4961 hci_dev_lock(hdev);
4962
4963 bacpy(&hdev->static_addr, &cp->bdaddr);
4964
Marcel Holtmann93690c22015-03-06 10:11:21 -08004965 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4966 if (err < 0)
4967 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004968
Marcel Holtmann93690c22015-03-06 10:11:21 -08004969 err = new_settings(hdev, sk);
4970
4971unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004972 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004973 return err;
4974}
4975
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004976static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4977 void *data, u16 len)
4978{
4979 struct mgmt_cp_set_scan_params *cp = data;
4980 __u16 interval, window;
4981 int err;
4982
Marcel Holtmann181d6952020-05-06 09:57:47 +02004983 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004984
4985 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004986 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4987 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004988
4989 interval = __le16_to_cpu(cp->interval);
4990
4991 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004992 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4993 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004994
4995 window = __le16_to_cpu(cp->window);
4996
4997 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004998 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4999 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005000
Marcel Holtmann899e1072013-10-14 09:55:32 -07005001 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005002 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5003 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005004
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005005 hci_dev_lock(hdev);
5006
5007 hdev->le_scan_interval = interval;
5008 hdev->le_scan_window = window;
5009
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005010 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5011 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005012
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005013 /* If background scan is running, restart it so new parameters are
5014 * loaded.
5015 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005016 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005017 hdev->discovery.state == DISCOVERY_STOPPED) {
5018 struct hci_request req;
5019
5020 hci_req_init(&req, hdev);
5021
5022 hci_req_add_le_scan_disable(&req);
5023 hci_req_add_le_passive_scan(&req);
5024
5025 hci_req_run(&req, NULL);
5026 }
5027
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005028 hci_dev_unlock(hdev);
5029
5030 return err;
5031}
5032
Marcel Holtmann1904a852015-01-11 13:50:44 -08005033static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5034 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005035{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005036 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005037
Marcel Holtmann181d6952020-05-06 09:57:47 +02005038 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005039
5040 hci_dev_lock(hdev);
5041
Johan Hedberg333ae952015-03-17 13:48:47 +02005042 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005043 if (!cmd)
5044 goto unlock;
5045
5046 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005047 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5048 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005049 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005050 struct mgmt_mode *cp = cmd->param;
5051
5052 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005053 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005054 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005055 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005056
Johan Hedberg33e38b32013-03-15 17:07:05 -05005057 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5058 new_settings(hdev, cmd->sk);
5059 }
5060
5061 mgmt_pending_remove(cmd);
5062
5063unlock:
5064 hci_dev_unlock(hdev);
5065}
5066
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005067static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005068 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005069{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005070 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005071 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005072 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005073 int err;
5074
Marcel Holtmann181d6952020-05-06 09:57:47 +02005075 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005076
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005077 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005078 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005079 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5080 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005081
Johan Hedberga7e80f22013-01-09 16:05:19 +02005082 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005083 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5084 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005085
Antti Julkuf6422ec2011-06-22 13:11:56 +03005086 hci_dev_lock(hdev);
5087
Johan Hedberg333ae952015-03-17 13:48:47 +02005088 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005089 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5090 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005091 goto unlock;
5092 }
5093
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005094 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005095 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5096 hdev);
5097 goto unlock;
5098 }
5099
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005100 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005101 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005102 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5103 hdev);
5104 new_settings(hdev, sk);
5105 goto unlock;
5106 }
5107
Johan Hedberg33e38b32013-03-15 17:07:05 -05005108 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5109 data, len);
5110 if (!cmd) {
5111 err = -ENOMEM;
5112 goto unlock;
5113 }
5114
5115 hci_req_init(&req, hdev);
5116
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005117 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005118
5119 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005120 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005121 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5122 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005123 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005124 }
5125
Johan Hedberg33e38b32013-03-15 17:07:05 -05005126unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005127 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005128
Antti Julkuf6422ec2011-06-22 13:11:56 +03005129 return err;
5130}
5131
Marcel Holtmann1904a852015-01-11 13:50:44 -08005132static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005133{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005134 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005135
Marcel Holtmann181d6952020-05-06 09:57:47 +02005136 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005137
5138 hci_dev_lock(hdev);
5139
Johan Hedberg333ae952015-03-17 13:48:47 +02005140 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005141 if (!cmd)
5142 goto unlock;
5143
5144 if (status) {
5145 u8 mgmt_err = mgmt_status(status);
5146
5147 /* We need to restore the flag if related HCI commands
5148 * failed.
5149 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005150 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005151
Johan Hedberga69e8372015-03-06 21:08:53 +02005152 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005153 } else {
5154 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5155 new_settings(hdev, cmd->sk);
5156 }
5157
5158 mgmt_pending_remove(cmd);
5159
5160unlock:
5161 hci_dev_unlock(hdev);
5162}
5163
5164static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5165{
5166 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005167 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005168 struct hci_request req;
5169 int err;
5170
Marcel Holtmann181d6952020-05-06 09:57:47 +02005171 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005172
5173 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5175 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005176
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005177 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005178 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5179 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005180
5181 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005182 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5183 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005184
5185 hci_dev_lock(hdev);
5186
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005187 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005188 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5189 goto unlock;
5190 }
5191
5192 if (!hdev_is_powered(hdev)) {
5193 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005194 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5195 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5196 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5197 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5198 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005199 }
5200
Marcel Holtmannce05d602015-03-13 02:11:03 -07005201 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005202
5203 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5204 if (err < 0)
5205 goto unlock;
5206
5207 err = new_settings(hdev, sk);
5208 goto unlock;
5209 }
5210
5211 /* Reject disabling when powered on */
5212 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005213 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5214 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005215 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005216 } else {
5217 /* When configuring a dual-mode controller to operate
5218 * with LE only and using a static address, then switching
5219 * BR/EDR back on is not allowed.
5220 *
5221 * Dual-mode controllers shall operate with the public
5222 * address as its identity address for BR/EDR and LE. So
5223 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005224 *
5225 * The same restrictions applies when secure connections
5226 * has been enabled. For BR/EDR this is a controller feature
5227 * while for LE it is a host stack feature. This means that
5228 * switching BR/EDR back on when secure connections has been
5229 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005230 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005231 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005232 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005233 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005234 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5235 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005236 goto unlock;
5237 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005238 }
5239
Johan Hedberg333ae952015-03-17 13:48:47 +02005240 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005241 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5242 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005243 goto unlock;
5244 }
5245
5246 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5247 if (!cmd) {
5248 err = -ENOMEM;
5249 goto unlock;
5250 }
5251
Johan Hedbergf2252572015-11-18 12:49:20 +02005252 /* We need to flip the bit already here so that
5253 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005254 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005255 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005256
5257 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005258
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005259 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005260 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005261
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005262 /* Since only the advertising data flags will change, there
5263 * is no need to update the scan response data.
5264 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005265 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005266
Johan Hedberg0663ca22013-10-02 13:43:14 +03005267 err = hci_req_run(&req, set_bredr_complete);
5268 if (err < 0)
5269 mgmt_pending_remove(cmd);
5270
5271unlock:
5272 hci_dev_unlock(hdev);
5273 return err;
5274}
5275
Johan Hedberga1443f52015-01-23 15:42:46 +02005276static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5277{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005278 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005279 struct mgmt_mode *cp;
5280
Marcel Holtmann181d6952020-05-06 09:57:47 +02005281 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005282
5283 hci_dev_lock(hdev);
5284
Johan Hedberg333ae952015-03-17 13:48:47 +02005285 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005286 if (!cmd)
5287 goto unlock;
5288
5289 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005290 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5291 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005292 goto remove;
5293 }
5294
5295 cp = cmd->param;
5296
5297 switch (cp->val) {
5298 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005299 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5300 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005301 break;
5302 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005303 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005304 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005305 break;
5306 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005307 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5308 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005309 break;
5310 }
5311
5312 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5313 new_settings(hdev, cmd->sk);
5314
5315remove:
5316 mgmt_pending_remove(cmd);
5317unlock:
5318 hci_dev_unlock(hdev);
5319}
5320
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005321static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5322 void *data, u16 len)
5323{
5324 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005325 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005326 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005327 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005328 int err;
5329
Marcel Holtmann181d6952020-05-06 09:57:47 +02005330 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005331
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005332 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005333 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005334 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5335 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005336
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005337 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005338 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005339 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005340 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5341 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005342
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005343 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005344 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005345 MGMT_STATUS_INVALID_PARAMS);
5346
5347 hci_dev_lock(hdev);
5348
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005349 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005350 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005351 bool changed;
5352
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005353 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005354 changed = !hci_dev_test_and_set_flag(hdev,
5355 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005356 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005357 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005358 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005359 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005360 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005361 changed = hci_dev_test_and_clear_flag(hdev,
5362 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005363 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005364 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005365
5366 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5367 if (err < 0)
5368 goto failed;
5369
5370 if (changed)
5371 err = new_settings(hdev, sk);
5372
5373 goto failed;
5374 }
5375
Johan Hedberg333ae952015-03-17 13:48:47 +02005376 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005377 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5378 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005379 goto failed;
5380 }
5381
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005382 val = !!cp->val;
5383
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005384 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5385 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005386 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5387 goto failed;
5388 }
5389
5390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5391 if (!cmd) {
5392 err = -ENOMEM;
5393 goto failed;
5394 }
5395
Johan Hedberga1443f52015-01-23 15:42:46 +02005396 hci_req_init(&req, hdev);
5397 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5398 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005399 if (err < 0) {
5400 mgmt_pending_remove(cmd);
5401 goto failed;
5402 }
5403
5404failed:
5405 hci_dev_unlock(hdev);
5406 return err;
5407}
5408
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005409static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5410 void *data, u16 len)
5411{
5412 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005413 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005414 int err;
5415
Marcel Holtmann181d6952020-05-06 09:57:47 +02005416 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005417
Johan Hedbergb97109792014-06-24 14:00:28 +03005418 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005419 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5420 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005421
5422 hci_dev_lock(hdev);
5423
5424 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005425 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005426 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005427 changed = hci_dev_test_and_clear_flag(hdev,
5428 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005429
Johan Hedbergb97109792014-06-24 14:00:28 +03005430 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005431 use_changed = !hci_dev_test_and_set_flag(hdev,
5432 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005433 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005434 use_changed = hci_dev_test_and_clear_flag(hdev,
5435 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005436
5437 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005438 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005439 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5440 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5441 sizeof(mode), &mode);
5442 }
5443
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005444 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5445 if (err < 0)
5446 goto unlock;
5447
5448 if (changed)
5449 err = new_settings(hdev, sk);
5450
5451unlock:
5452 hci_dev_unlock(hdev);
5453 return err;
5454}
5455
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005456static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5457 u16 len)
5458{
5459 struct mgmt_cp_set_privacy *cp = cp_data;
5460 bool changed;
5461 int err;
5462
Marcel Holtmann181d6952020-05-06 09:57:47 +02005463 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005464
5465 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005466 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5467 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005468
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005469 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005470 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5471 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005472
5473 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005474 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5475 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005476
5477 hci_dev_lock(hdev);
5478
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005479 /* If user space supports this command it is also expected to
5480 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5481 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005482 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005483
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005484 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005485 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005486 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005487 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305488 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005489 if (cp->privacy == 0x02)
5490 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5491 else
5492 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005493 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005494 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005495 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005496 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305497 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005498 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005499 }
5500
5501 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5502 if (err < 0)
5503 goto unlock;
5504
5505 if (changed)
5506 err = new_settings(hdev, sk);
5507
5508unlock:
5509 hci_dev_unlock(hdev);
5510 return err;
5511}
5512
Johan Hedberg41edf162014-02-18 10:19:35 +02005513static bool irk_is_valid(struct mgmt_irk_info *irk)
5514{
5515 switch (irk->addr.type) {
5516 case BDADDR_LE_PUBLIC:
5517 return true;
5518
5519 case BDADDR_LE_RANDOM:
5520 /* Two most significant bits shall be set */
5521 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5522 return false;
5523 return true;
5524 }
5525
5526 return false;
5527}
5528
5529static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5530 u16 len)
5531{
5532 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005533 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5534 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005535 u16 irk_count, expected_len;
5536 int i, err;
5537
Marcel Holtmann181d6952020-05-06 09:57:47 +02005538 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005539
5540 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005541 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5542 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005543
5544 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005545 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005546 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5547 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005548 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5549 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005550 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005551
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005552 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005553 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005554 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5555 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5557 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005558 }
5559
Marcel Holtmann181d6952020-05-06 09:57:47 +02005560 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005561
5562 for (i = 0; i < irk_count; i++) {
5563 struct mgmt_irk_info *key = &cp->irks[i];
5564
5565 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005566 return mgmt_cmd_status(sk, hdev->id,
5567 MGMT_OP_LOAD_IRKS,
5568 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005569 }
5570
5571 hci_dev_lock(hdev);
5572
5573 hci_smp_irks_clear(hdev);
5574
5575 for (i = 0; i < irk_count; i++) {
5576 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005577
Alain Michaud600a8742020-01-07 00:43:17 +00005578 if (hci_is_blocked_key(hdev,
5579 HCI_BLOCKED_KEY_TYPE_IRK,
5580 irk->val)) {
5581 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5582 &irk->addr.bdaddr);
5583 continue;
5584 }
5585
Johan Hedberg85813a72015-10-21 18:02:59 +03005586 hci_add_irk(hdev, &irk->addr.bdaddr,
5587 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005588 BDADDR_ANY);
5589 }
5590
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005591 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005592
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005593 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005594
5595 hci_dev_unlock(hdev);
5596
5597 return err;
5598}
5599
Johan Hedberg3f706b72013-01-20 14:27:16 +02005600static bool ltk_is_valid(struct mgmt_ltk_info *key)
5601{
5602 if (key->master != 0x00 && key->master != 0x01)
5603 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005604
5605 switch (key->addr.type) {
5606 case BDADDR_LE_PUBLIC:
5607 return true;
5608
5609 case BDADDR_LE_RANDOM:
5610 /* Two most significant bits shall be set */
5611 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5612 return false;
5613 return true;
5614 }
5615
5616 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005617}
5618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005619static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005620 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005621{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005622 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005623 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5624 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005625 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005626 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005627
Marcel Holtmann181d6952020-05-06 09:57:47 +02005628 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005629
5630 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005631 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5632 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005633
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005634 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005635 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005636 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5637 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005638 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5639 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005640 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005641
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005642 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005643 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005644 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5645 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005646 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5647 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005648 }
5649
Marcel Holtmann181d6952020-05-06 09:57:47 +02005650 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005651
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005652 for (i = 0; i < key_count; i++) {
5653 struct mgmt_ltk_info *key = &cp->keys[i];
5654
Johan Hedberg3f706b72013-01-20 14:27:16 +02005655 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005656 return mgmt_cmd_status(sk, hdev->id,
5657 MGMT_OP_LOAD_LONG_TERM_KEYS,
5658 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005659 }
5660
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005661 hci_dev_lock(hdev);
5662
5663 hci_smp_ltks_clear(hdev);
5664
5665 for (i = 0; i < key_count; i++) {
5666 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005667 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005668
Alain Michaud600a8742020-01-07 00:43:17 +00005669 if (hci_is_blocked_key(hdev,
5670 HCI_BLOCKED_KEY_TYPE_LTK,
5671 key->val)) {
5672 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5673 &key->addr.bdaddr);
5674 continue;
5675 }
5676
Johan Hedberg61b43352014-05-29 19:36:53 +03005677 switch (key->type) {
5678 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005679 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005680 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005681 break;
5682 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005683 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005684 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005685 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005686 case MGMT_LTK_P256_UNAUTH:
5687 authenticated = 0x00;
5688 type = SMP_LTK_P256;
5689 break;
5690 case MGMT_LTK_P256_AUTH:
5691 authenticated = 0x01;
5692 type = SMP_LTK_P256;
5693 break;
5694 case MGMT_LTK_P256_DEBUG:
5695 authenticated = 0x00;
5696 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005697 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005698 default:
5699 continue;
5700 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005701
Johan Hedberg85813a72015-10-21 18:02:59 +03005702 hci_add_ltk(hdev, &key->addr.bdaddr,
5703 le_addr_type(key->addr.type), type, authenticated,
5704 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005705 }
5706
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005707 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005708 NULL, 0);
5709
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005710 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005711
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005712 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005713}
5714
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005715static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005716{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005717 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005718 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005719 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005720
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005721 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005722
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005723 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005724 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005725 rp.tx_power = conn->tx_power;
5726 rp.max_tx_power = conn->max_tx_power;
5727 } else {
5728 rp.rssi = HCI_RSSI_INVALID;
5729 rp.tx_power = HCI_TX_POWER_INVALID;
5730 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005731 }
5732
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005733 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5734 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005735
5736 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005737 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005738
5739 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005740}
5741
Marcel Holtmann1904a852015-01-11 13:50:44 -08005742static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5743 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005744{
5745 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005746 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005747 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005748 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005749 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005750
Marcel Holtmann181d6952020-05-06 09:57:47 +02005751 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005752
5753 hci_dev_lock(hdev);
5754
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005755 /* Commands sent in request are either Read RSSI or Read Transmit Power
5756 * Level so we check which one was last sent to retrieve connection
5757 * handle. Both commands have handle as first parameter so it's safe to
5758 * cast data on the same command struct.
5759 *
5760 * First command sent is always Read RSSI and we fail only if it fails.
5761 * In other case we simply override error to indicate success as we
5762 * already remembered if TX power value is actually valid.
5763 */
5764 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5765 if (!cp) {
5766 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005767 status = MGMT_STATUS_SUCCESS;
5768 } else {
5769 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005770 }
5771
5772 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005773 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005774 goto unlock;
5775 }
5776
5777 handle = __le16_to_cpu(cp->handle);
5778 conn = hci_conn_hash_lookup_handle(hdev, handle);
5779 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005780 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5781 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005782 goto unlock;
5783 }
5784
Johan Hedberg333ae952015-03-17 13:48:47 +02005785 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005786 if (!cmd)
5787 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005788
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005789 cmd->cmd_complete(cmd, status);
5790 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005791
5792unlock:
5793 hci_dev_unlock(hdev);
5794}
5795
5796static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5797 u16 len)
5798{
5799 struct mgmt_cp_get_conn_info *cp = data;
5800 struct mgmt_rp_get_conn_info rp;
5801 struct hci_conn *conn;
5802 unsigned long conn_info_age;
5803 int err = 0;
5804
Marcel Holtmann181d6952020-05-06 09:57:47 +02005805 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005806
5807 memset(&rp, 0, sizeof(rp));
5808 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5809 rp.addr.type = cp->addr.type;
5810
5811 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005812 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5813 MGMT_STATUS_INVALID_PARAMS,
5814 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005815
5816 hci_dev_lock(hdev);
5817
5818 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005819 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5820 MGMT_STATUS_NOT_POWERED, &rp,
5821 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005822 goto unlock;
5823 }
5824
5825 if (cp->addr.type == BDADDR_BREDR)
5826 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5827 &cp->addr.bdaddr);
5828 else
5829 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5830
5831 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005832 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5833 MGMT_STATUS_NOT_CONNECTED, &rp,
5834 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005835 goto unlock;
5836 }
5837
Johan Hedberg333ae952015-03-17 13:48:47 +02005838 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005839 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5840 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005841 goto unlock;
5842 }
5843
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005844 /* To avoid client trying to guess when to poll again for information we
5845 * calculate conn info age as random value between min/max set in hdev.
5846 */
5847 conn_info_age = hdev->conn_info_min_age +
5848 prandom_u32_max(hdev->conn_info_max_age -
5849 hdev->conn_info_min_age);
5850
5851 /* Query controller to refresh cached values if they are too old or were
5852 * never read.
5853 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005854 if (time_after(jiffies, conn->conn_info_timestamp +
5855 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005856 !conn->conn_info_timestamp) {
5857 struct hci_request req;
5858 struct hci_cp_read_tx_power req_txp_cp;
5859 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005860 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005861
5862 hci_req_init(&req, hdev);
5863 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5864 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5865 &req_rssi_cp);
5866
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005867 /* For LE links TX power does not change thus we don't need to
5868 * query for it once value is known.
5869 */
5870 if (!bdaddr_type_is_le(cp->addr.type) ||
5871 conn->tx_power == HCI_TX_POWER_INVALID) {
5872 req_txp_cp.handle = cpu_to_le16(conn->handle);
5873 req_txp_cp.type = 0x00;
5874 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5875 sizeof(req_txp_cp), &req_txp_cp);
5876 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005877
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005878 /* Max TX power needs to be read only once per connection */
5879 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5880 req_txp_cp.handle = cpu_to_le16(conn->handle);
5881 req_txp_cp.type = 0x01;
5882 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5883 sizeof(req_txp_cp), &req_txp_cp);
5884 }
5885
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005886 err = hci_req_run(&req, conn_info_refresh_complete);
5887 if (err < 0)
5888 goto unlock;
5889
5890 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5891 data, len);
5892 if (!cmd) {
5893 err = -ENOMEM;
5894 goto unlock;
5895 }
5896
5897 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005898 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005899 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005900
5901 conn->conn_info_timestamp = jiffies;
5902 } else {
5903 /* Cache is valid, just reply with values cached in hci_conn */
5904 rp.rssi = conn->rssi;
5905 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005906 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005907
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005908 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5909 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005910 }
5911
5912unlock:
5913 hci_dev_unlock(hdev);
5914 return err;
5915}
5916
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005917static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005918{
5919 struct hci_conn *conn = cmd->user_data;
5920 struct mgmt_rp_get_clock_info rp;
5921 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005922 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005923
5924 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005925 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005926
5927 if (status)
5928 goto complete;
5929
5930 hdev = hci_dev_get(cmd->index);
5931 if (hdev) {
5932 rp.local_clock = cpu_to_le32(hdev->clock);
5933 hci_dev_put(hdev);
5934 }
5935
5936 if (conn) {
5937 rp.piconet_clock = cpu_to_le32(conn->clock);
5938 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5939 }
5940
5941complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005942 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5943 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005944
5945 if (conn) {
5946 hci_conn_drop(conn);
5947 hci_conn_put(conn);
5948 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005949
5950 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005951}
5952
Marcel Holtmann1904a852015-01-11 13:50:44 -08005953static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005954{
Johan Hedberg95868422014-06-28 17:54:07 +03005955 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005956 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005957 struct hci_conn *conn;
5958
Marcel Holtmann181d6952020-05-06 09:57:47 +02005959 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03005960
5961 hci_dev_lock(hdev);
5962
5963 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5964 if (!hci_cp)
5965 goto unlock;
5966
5967 if (hci_cp->which) {
5968 u16 handle = __le16_to_cpu(hci_cp->handle);
5969 conn = hci_conn_hash_lookup_handle(hdev, handle);
5970 } else {
5971 conn = NULL;
5972 }
5973
Johan Hedberg333ae952015-03-17 13:48:47 +02005974 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005975 if (!cmd)
5976 goto unlock;
5977
Johan Hedberg69487372014-12-05 13:36:07 +02005978 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005979 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005980
5981unlock:
5982 hci_dev_unlock(hdev);
5983}
5984
5985static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5986 u16 len)
5987{
5988 struct mgmt_cp_get_clock_info *cp = data;
5989 struct mgmt_rp_get_clock_info rp;
5990 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005991 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005992 struct hci_request req;
5993 struct hci_conn *conn;
5994 int err;
5995
Marcel Holtmann181d6952020-05-06 09:57:47 +02005996 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03005997
5998 memset(&rp, 0, sizeof(rp));
5999 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6000 rp.addr.type = cp->addr.type;
6001
6002 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006003 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6004 MGMT_STATUS_INVALID_PARAMS,
6005 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006006
6007 hci_dev_lock(hdev);
6008
6009 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006010 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6011 MGMT_STATUS_NOT_POWERED, &rp,
6012 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006013 goto unlock;
6014 }
6015
6016 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6017 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6018 &cp->addr.bdaddr);
6019 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006020 err = mgmt_cmd_complete(sk, hdev->id,
6021 MGMT_OP_GET_CLOCK_INFO,
6022 MGMT_STATUS_NOT_CONNECTED,
6023 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006024 goto unlock;
6025 }
6026 } else {
6027 conn = NULL;
6028 }
6029
6030 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6031 if (!cmd) {
6032 err = -ENOMEM;
6033 goto unlock;
6034 }
6035
Johan Hedberg69487372014-12-05 13:36:07 +02006036 cmd->cmd_complete = clock_info_cmd_complete;
6037
Johan Hedberg95868422014-06-28 17:54:07 +03006038 hci_req_init(&req, hdev);
6039
6040 memset(&hci_cp, 0, sizeof(hci_cp));
6041 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6042
6043 if (conn) {
6044 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006045 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006046
6047 hci_cp.handle = cpu_to_le16(conn->handle);
6048 hci_cp.which = 0x01; /* Piconet clock */
6049 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6050 }
6051
6052 err = hci_req_run(&req, get_clock_info_complete);
6053 if (err < 0)
6054 mgmt_pending_remove(cmd);
6055
6056unlock:
6057 hci_dev_unlock(hdev);
6058 return err;
6059}
6060
Johan Hedberg5a154e62014-12-19 22:26:02 +02006061static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6062{
6063 struct hci_conn *conn;
6064
6065 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6066 if (!conn)
6067 return false;
6068
6069 if (conn->dst_type != type)
6070 return false;
6071
6072 if (conn->state != BT_CONNECTED)
6073 return false;
6074
6075 return true;
6076}
6077
6078/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006079static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006080 u8 addr_type, u8 auto_connect)
6081{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006082 struct hci_conn_params *params;
6083
6084 params = hci_conn_params_add(hdev, addr, addr_type);
6085 if (!params)
6086 return -EIO;
6087
6088 if (params->auto_connect == auto_connect)
6089 return 0;
6090
6091 list_del_init(&params->action);
6092
6093 switch (auto_connect) {
6094 case HCI_AUTO_CONN_DISABLED:
6095 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006096 /* If auto connect is being disabled when we're trying to
6097 * connect to device, keep connecting.
6098 */
6099 if (params->explicit_connect)
6100 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006101 break;
6102 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006103 if (params->explicit_connect)
6104 list_add(&params->action, &hdev->pend_le_conns);
6105 else
6106 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006107 break;
6108 case HCI_AUTO_CONN_DIRECT:
6109 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006110 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006111 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006112 break;
6113 }
6114
6115 params->auto_connect = auto_connect;
6116
Marcel Holtmann181d6952020-05-06 09:57:47 +02006117 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6118 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006119
6120 return 0;
6121}
6122
Marcel Holtmann8afef092014-06-29 22:28:34 +02006123static void device_added(struct sock *sk, struct hci_dev *hdev,
6124 bdaddr_t *bdaddr, u8 type, u8 action)
6125{
6126 struct mgmt_ev_device_added ev;
6127
6128 bacpy(&ev.addr.bdaddr, bdaddr);
6129 ev.addr.type = type;
6130 ev.action = action;
6131
6132 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6133}
6134
Marcel Holtmann2faade52014-06-29 19:44:03 +02006135static int add_device(struct sock *sk, struct hci_dev *hdev,
6136 void *data, u16 len)
6137{
6138 struct mgmt_cp_add_device *cp = data;
6139 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006140 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006141 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006142 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006143
Marcel Holtmann181d6952020-05-06 09:57:47 +02006144 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006145
Johan Hedberg66593582014-07-09 12:59:14 +03006146 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006147 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006148 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6149 MGMT_STATUS_INVALID_PARAMS,
6150 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006151
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006152 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006153 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6154 MGMT_STATUS_INVALID_PARAMS,
6155 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006156
6157 hci_dev_lock(hdev);
6158
Johan Hedberg66593582014-07-09 12:59:14 +03006159 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006160 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006161 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006162 err = mgmt_cmd_complete(sk, hdev->id,
6163 MGMT_OP_ADD_DEVICE,
6164 MGMT_STATUS_INVALID_PARAMS,
6165 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006166 goto unlock;
6167 }
6168
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006169 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6170 &cp->addr.bdaddr,
6171 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006172 if (err)
6173 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006174
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006175 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006176
Johan Hedberg66593582014-07-09 12:59:14 +03006177 goto added;
6178 }
6179
Johan Hedberg85813a72015-10-21 18:02:59 +03006180 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006181
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006182 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006183 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006184 else if (cp->action == 0x01)
6185 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006186 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006187 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006188
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006189 /* Kernel internally uses conn_params with resolvable private
6190 * address, but Add Device allows only identity addresses.
6191 * Make sure it is enforced before calling
6192 * hci_conn_params_lookup.
6193 */
6194 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006195 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6196 MGMT_STATUS_INVALID_PARAMS,
6197 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006198 goto unlock;
6199 }
6200
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006201 /* If the connection parameters don't exist for this device,
6202 * they will be created and configured with defaults.
6203 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006204 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006205 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006206 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6207 MGMT_STATUS_FAILED, &cp->addr,
6208 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006209 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006210 } else {
6211 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6212 addr_type);
6213 if (params)
6214 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006215 }
6216
Johan Hedberg51d7a942015-11-11 08:11:18 +02006217 hci_update_background_scan(hdev);
6218
Johan Hedberg66593582014-07-09 12:59:14 +03006219added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006220 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006221 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6222 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006223
Johan Hedberg51d7a942015-11-11 08:11:18 +02006224 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6225 MGMT_STATUS_SUCCESS, &cp->addr,
6226 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006227
6228unlock:
6229 hci_dev_unlock(hdev);
6230 return err;
6231}
6232
Marcel Holtmann8afef092014-06-29 22:28:34 +02006233static void device_removed(struct sock *sk, struct hci_dev *hdev,
6234 bdaddr_t *bdaddr, u8 type)
6235{
6236 struct mgmt_ev_device_removed ev;
6237
6238 bacpy(&ev.addr.bdaddr, bdaddr);
6239 ev.addr.type = type;
6240
6241 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6242}
6243
Marcel Holtmann2faade52014-06-29 19:44:03 +02006244static int remove_device(struct sock *sk, struct hci_dev *hdev,
6245 void *data, u16 len)
6246{
6247 struct mgmt_cp_remove_device *cp = data;
6248 int err;
6249
Marcel Holtmann181d6952020-05-06 09:57:47 +02006250 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006251
6252 hci_dev_lock(hdev);
6253
6254 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006255 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006256 u8 addr_type;
6257
Johan Hedberg66593582014-07-09 12:59:14 +03006258 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006259 err = mgmt_cmd_complete(sk, hdev->id,
6260 MGMT_OP_REMOVE_DEVICE,
6261 MGMT_STATUS_INVALID_PARAMS,
6262 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006263 goto unlock;
6264 }
6265
Johan Hedberg66593582014-07-09 12:59:14 +03006266 if (cp->addr.type == BDADDR_BREDR) {
6267 err = hci_bdaddr_list_del(&hdev->whitelist,
6268 &cp->addr.bdaddr,
6269 cp->addr.type);
6270 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006271 err = mgmt_cmd_complete(sk, hdev->id,
6272 MGMT_OP_REMOVE_DEVICE,
6273 MGMT_STATUS_INVALID_PARAMS,
6274 &cp->addr,
6275 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006276 goto unlock;
6277 }
6278
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006279 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006280
Johan Hedberg66593582014-07-09 12:59:14 +03006281 device_removed(sk, hdev, &cp->addr.bdaddr,
6282 cp->addr.type);
6283 goto complete;
6284 }
6285
Johan Hedberg85813a72015-10-21 18:02:59 +03006286 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006287
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006288 /* Kernel internally uses conn_params with resolvable private
6289 * address, but Remove Device allows only identity addresses.
6290 * Make sure it is enforced before calling
6291 * hci_conn_params_lookup.
6292 */
6293 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006294 err = mgmt_cmd_complete(sk, hdev->id,
6295 MGMT_OP_REMOVE_DEVICE,
6296 MGMT_STATUS_INVALID_PARAMS,
6297 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006298 goto unlock;
6299 }
6300
Johan Hedbergc71593d2014-07-02 17:37:28 +03006301 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6302 addr_type);
6303 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006304 err = mgmt_cmd_complete(sk, hdev->id,
6305 MGMT_OP_REMOVE_DEVICE,
6306 MGMT_STATUS_INVALID_PARAMS,
6307 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006308 goto unlock;
6309 }
6310
Johan Hedberg679d2b62015-10-16 10:07:52 +03006311 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6312 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006313 err = mgmt_cmd_complete(sk, hdev->id,
6314 MGMT_OP_REMOVE_DEVICE,
6315 MGMT_STATUS_INVALID_PARAMS,
6316 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006317 goto unlock;
6318 }
6319
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006320 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006321 list_del(&params->list);
6322 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006323 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006324
6325 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006326 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006327 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006328 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006329
Marcel Holtmann2faade52014-06-29 19:44:03 +02006330 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006331 err = mgmt_cmd_complete(sk, hdev->id,
6332 MGMT_OP_REMOVE_DEVICE,
6333 MGMT_STATUS_INVALID_PARAMS,
6334 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006335 goto unlock;
6336 }
6337
Johan Hedberg66593582014-07-09 12:59:14 +03006338 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6339 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6340 list_del(&b->list);
6341 kfree(b);
6342 }
6343
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006344 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006345
Johan Hedberg19de0822014-07-06 13:06:51 +03006346 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6347 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6348 continue;
6349 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006350 if (p->explicit_connect) {
6351 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6352 continue;
6353 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006354 list_del(&p->action);
6355 list_del(&p->list);
6356 kfree(p);
6357 }
6358
Marcel Holtmann181d6952020-05-06 09:57:47 +02006359 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006360
Johan Hedberg51d7a942015-11-11 08:11:18 +02006361 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006362 }
6363
Johan Hedberg66593582014-07-09 12:59:14 +03006364complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006365 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6366 MGMT_STATUS_SUCCESS, &cp->addr,
6367 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006368unlock:
6369 hci_dev_unlock(hdev);
6370 return err;
6371}
6372
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006373static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6374 u16 len)
6375{
6376 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006377 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6378 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006379 u16 param_count, expected_len;
6380 int i;
6381
6382 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006383 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6384 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006385
6386 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006387 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006388 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6389 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006390 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6391 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006392 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006393
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006394 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006395 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006396 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6397 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006398 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006400 }
6401
Marcel Holtmann181d6952020-05-06 09:57:47 +02006402 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006403
6404 hci_dev_lock(hdev);
6405
6406 hci_conn_params_clear_disabled(hdev);
6407
6408 for (i = 0; i < param_count; i++) {
6409 struct mgmt_conn_param *param = &cp->params[i];
6410 struct hci_conn_params *hci_param;
6411 u16 min, max, latency, timeout;
6412 u8 addr_type;
6413
Marcel Holtmann181d6952020-05-06 09:57:47 +02006414 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6415 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006416
6417 if (param->addr.type == BDADDR_LE_PUBLIC) {
6418 addr_type = ADDR_LE_DEV_PUBLIC;
6419 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6420 addr_type = ADDR_LE_DEV_RANDOM;
6421 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006422 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006423 continue;
6424 }
6425
6426 min = le16_to_cpu(param->min_interval);
6427 max = le16_to_cpu(param->max_interval);
6428 latency = le16_to_cpu(param->latency);
6429 timeout = le16_to_cpu(param->timeout);
6430
Marcel Holtmann181d6952020-05-06 09:57:47 +02006431 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6432 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006433
6434 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006435 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006436 continue;
6437 }
6438
6439 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6440 addr_type);
6441 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006442 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006443 continue;
6444 }
6445
6446 hci_param->conn_min_interval = min;
6447 hci_param->conn_max_interval = max;
6448 hci_param->conn_latency = latency;
6449 hci_param->supervision_timeout = timeout;
6450 }
6451
6452 hci_dev_unlock(hdev);
6453
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006454 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6455 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006456}
6457
Marcel Holtmanndbece372014-07-04 18:11:55 +02006458static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6459 void *data, u16 len)
6460{
6461 struct mgmt_cp_set_external_config *cp = data;
6462 bool changed;
6463 int err;
6464
Marcel Holtmann181d6952020-05-06 09:57:47 +02006465 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006466
6467 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006468 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6469 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006470
6471 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006472 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6473 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006474
6475 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006476 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6477 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006478
6479 hci_dev_lock(hdev);
6480
6481 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006482 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006483 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006484 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006485
6486 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6487 if (err < 0)
6488 goto unlock;
6489
6490 if (!changed)
6491 goto unlock;
6492
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006493 err = new_options(hdev, sk);
6494
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006495 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006496 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006497
Marcel Holtmann516018a2015-03-13 02:11:04 -07006498 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006499 hci_dev_set_flag(hdev, HCI_CONFIG);
6500 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006501
6502 queue_work(hdev->req_workqueue, &hdev->power_on);
6503 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006504 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006505 mgmt_index_added(hdev);
6506 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006507 }
6508
6509unlock:
6510 hci_dev_unlock(hdev);
6511 return err;
6512}
6513
Marcel Holtmann9713c172014-07-06 12:11:15 +02006514static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6515 void *data, u16 len)
6516{
6517 struct mgmt_cp_set_public_address *cp = data;
6518 bool changed;
6519 int err;
6520
Marcel Holtmann181d6952020-05-06 09:57:47 +02006521 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006522
6523 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006524 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6525 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006526
6527 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006528 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6529 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006530
6531 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006532 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6533 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006534
6535 hci_dev_lock(hdev);
6536
6537 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6538 bacpy(&hdev->public_addr, &cp->bdaddr);
6539
6540 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6541 if (err < 0)
6542 goto unlock;
6543
6544 if (!changed)
6545 goto unlock;
6546
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006547 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006548 err = new_options(hdev, sk);
6549
6550 if (is_configured(hdev)) {
6551 mgmt_index_removed(hdev);
6552
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006553 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006554
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006555 hci_dev_set_flag(hdev, HCI_CONFIG);
6556 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006557
6558 queue_work(hdev->req_workqueue, &hdev->power_on);
6559 }
6560
6561unlock:
6562 hci_dev_unlock(hdev);
6563 return err;
6564}
6565
Johan Hedberg40f66c02015-04-07 21:52:22 +03006566static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6567 u16 opcode, struct sk_buff *skb)
6568{
6569 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6570 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6571 u8 *h192, *r192, *h256, *r256;
6572 struct mgmt_pending_cmd *cmd;
6573 u16 eir_len;
6574 int err;
6575
Marcel Holtmann181d6952020-05-06 09:57:47 +02006576 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006577
6578 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6579 if (!cmd)
6580 return;
6581
6582 mgmt_cp = cmd->param;
6583
6584 if (status) {
6585 status = mgmt_status(status);
6586 eir_len = 0;
6587
6588 h192 = NULL;
6589 r192 = NULL;
6590 h256 = NULL;
6591 r256 = NULL;
6592 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6593 struct hci_rp_read_local_oob_data *rp;
6594
6595 if (skb->len != sizeof(*rp)) {
6596 status = MGMT_STATUS_FAILED;
6597 eir_len = 0;
6598 } else {
6599 status = MGMT_STATUS_SUCCESS;
6600 rp = (void *)skb->data;
6601
6602 eir_len = 5 + 18 + 18;
6603 h192 = rp->hash;
6604 r192 = rp->rand;
6605 h256 = NULL;
6606 r256 = NULL;
6607 }
6608 } else {
6609 struct hci_rp_read_local_oob_ext_data *rp;
6610
6611 if (skb->len != sizeof(*rp)) {
6612 status = MGMT_STATUS_FAILED;
6613 eir_len = 0;
6614 } else {
6615 status = MGMT_STATUS_SUCCESS;
6616 rp = (void *)skb->data;
6617
6618 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6619 eir_len = 5 + 18 + 18;
6620 h192 = NULL;
6621 r192 = NULL;
6622 } else {
6623 eir_len = 5 + 18 + 18 + 18 + 18;
6624 h192 = rp->hash192;
6625 r192 = rp->rand192;
6626 }
6627
6628 h256 = rp->hash256;
6629 r256 = rp->rand256;
6630 }
6631 }
6632
6633 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6634 if (!mgmt_rp)
6635 goto done;
6636
6637 if (status)
6638 goto send_rsp;
6639
6640 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6641 hdev->dev_class, 3);
6642
6643 if (h192 && r192) {
6644 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6645 EIR_SSP_HASH_C192, h192, 16);
6646 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6647 EIR_SSP_RAND_R192, r192, 16);
6648 }
6649
6650 if (h256 && r256) {
6651 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6652 EIR_SSP_HASH_C256, h256, 16);
6653 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6654 EIR_SSP_RAND_R256, r256, 16);
6655 }
6656
6657send_rsp:
6658 mgmt_rp->type = mgmt_cp->type;
6659 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6660
6661 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6662 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6663 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6664 if (err < 0 || status)
6665 goto done;
6666
6667 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6668
6669 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6670 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6671 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6672done:
6673 kfree(mgmt_rp);
6674 mgmt_pending_remove(cmd);
6675}
6676
6677static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6678 struct mgmt_cp_read_local_oob_ext_data *cp)
6679{
6680 struct mgmt_pending_cmd *cmd;
6681 struct hci_request req;
6682 int err;
6683
6684 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6685 cp, sizeof(*cp));
6686 if (!cmd)
6687 return -ENOMEM;
6688
6689 hci_req_init(&req, hdev);
6690
6691 if (bredr_sc_enabled(hdev))
6692 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6693 else
6694 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6695
6696 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6697 if (err < 0) {
6698 mgmt_pending_remove(cmd);
6699 return err;
6700 }
6701
6702 return 0;
6703}
6704
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006705static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6706 void *data, u16 data_len)
6707{
6708 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6709 struct mgmt_rp_read_local_oob_ext_data *rp;
6710 size_t rp_len;
6711 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006712 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006713 int err;
6714
Marcel Holtmann181d6952020-05-06 09:57:47 +02006715 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006716
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006717 if (hdev_is_powered(hdev)) {
6718 switch (cp->type) {
6719 case BIT(BDADDR_BREDR):
6720 status = mgmt_bredr_support(hdev);
6721 if (status)
6722 eir_len = 0;
6723 else
6724 eir_len = 5;
6725 break;
6726 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6727 status = mgmt_le_support(hdev);
6728 if (status)
6729 eir_len = 0;
6730 else
6731 eir_len = 9 + 3 + 18 + 18 + 3;
6732 break;
6733 default:
6734 status = MGMT_STATUS_INVALID_PARAMS;
6735 eir_len = 0;
6736 break;
6737 }
6738 } else {
6739 status = MGMT_STATUS_NOT_POWERED;
6740 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006741 }
6742
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006743 rp_len = sizeof(*rp) + eir_len;
6744 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006745 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006746 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006747
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006748 if (status)
6749 goto complete;
6750
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006751 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006752
6753 eir_len = 0;
6754 switch (cp->type) {
6755 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006756 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6757 err = read_local_ssp_oob_req(hdev, sk, cp);
6758 hci_dev_unlock(hdev);
6759 if (!err)
6760 goto done;
6761
6762 status = MGMT_STATUS_FAILED;
6763 goto complete;
6764 } else {
6765 eir_len = eir_append_data(rp->eir, eir_len,
6766 EIR_CLASS_OF_DEV,
6767 hdev->dev_class, 3);
6768 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006769 break;
6770 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006771 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6772 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006773 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006774 status = MGMT_STATUS_FAILED;
6775 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006776 }
6777
Marcel Holtmanne2135682015-04-02 12:00:58 -07006778 /* This should return the active RPA, but since the RPA
6779 * is only programmed on demand, it is really hard to fill
6780 * this in at the moment. For now disallow retrieving
6781 * local out-of-band data when privacy is in use.
6782 *
6783 * Returning the identity address will not help here since
6784 * pairing happens before the identity resolving key is
6785 * known and thus the connection establishment happens
6786 * based on the RPA and not the identity address.
6787 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006788 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006789 hci_dev_unlock(hdev);
6790 status = MGMT_STATUS_REJECTED;
6791 goto complete;
6792 }
6793
6794 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6795 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6796 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6797 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006798 memcpy(addr, &hdev->static_addr, 6);
6799 addr[6] = 0x01;
6800 } else {
6801 memcpy(addr, &hdev->bdaddr, 6);
6802 addr[6] = 0x00;
6803 }
6804
6805 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6806 addr, sizeof(addr));
6807
6808 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6809 role = 0x02;
6810 else
6811 role = 0x01;
6812
6813 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6814 &role, sizeof(role));
6815
Marcel Holtmann5082a592015-03-16 12:39:00 -07006816 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6817 eir_len = eir_append_data(rp->eir, eir_len,
6818 EIR_LE_SC_CONFIRM,
6819 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006820
Marcel Holtmann5082a592015-03-16 12:39:00 -07006821 eir_len = eir_append_data(rp->eir, eir_len,
6822 EIR_LE_SC_RANDOM,
6823 rand, sizeof(rand));
6824 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006825
Johan Hedbergf2252572015-11-18 12:49:20 +02006826 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006827
6828 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6829 flags |= LE_AD_NO_BREDR;
6830
6831 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6832 &flags, sizeof(flags));
6833 break;
6834 }
6835
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006836 hci_dev_unlock(hdev);
6837
Marcel Holtmann72000df2015-03-16 16:11:21 -07006838 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6839
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006840 status = MGMT_STATUS_SUCCESS;
6841
6842complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006843 rp->type = cp->type;
6844 rp->eir_len = cpu_to_le16(eir_len);
6845
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006846 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006847 status, rp, sizeof(*rp) + eir_len);
6848 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006849 goto done;
6850
6851 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6852 rp, sizeof(*rp) + eir_len,
6853 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006854
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006855done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006856 kfree(rp);
6857
6858 return err;
6859}
6860
Arman Uguray089fa8c2015-03-25 18:53:45 -07006861static u32 get_supported_adv_flags(struct hci_dev *hdev)
6862{
6863 u32 flags = 0;
6864
6865 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6866 flags |= MGMT_ADV_FLAG_DISCOV;
6867 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6868 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006869 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006870 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006871
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306872 /* In extended adv TX_POWER returned from Set Adv Param
6873 * will be always valid.
6874 */
6875 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6876 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006877 flags |= MGMT_ADV_FLAG_TX_POWER;
6878
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306879 if (ext_adv_capable(hdev)) {
6880 flags |= MGMT_ADV_FLAG_SEC_1M;
6881
6882 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6883 flags |= MGMT_ADV_FLAG_SEC_2M;
6884
6885 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6886 flags |= MGMT_ADV_FLAG_SEC_CODED;
6887 }
6888
Arman Uguray089fa8c2015-03-25 18:53:45 -07006889 return flags;
6890}
6891
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006892static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6893 void *data, u16 data_len)
6894{
6895 struct mgmt_rp_read_adv_features *rp;
6896 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006897 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006898 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006899 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006900 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006901
Marcel Holtmann181d6952020-05-06 09:57:47 +02006902 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006903
Arman Uguray089fa8c2015-03-25 18:53:45 -07006904 if (!lmp_le_capable(hdev))
6905 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6906 MGMT_STATUS_REJECTED);
6907
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006908 hci_dev_lock(hdev);
6909
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006910 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006911 rp = kmalloc(rp_len, GFP_ATOMIC);
6912 if (!rp) {
6913 hci_dev_unlock(hdev);
6914 return -ENOMEM;
6915 }
6916
Arman Uguray089fa8c2015-03-25 18:53:45 -07006917 supported_flags = get_supported_adv_flags(hdev);
6918
6919 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006920 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6921 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006922 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006923 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006924
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006925 instance = rp->instance;
6926 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6927 *instance = adv_instance->instance;
6928 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006929 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006930
6931 hci_dev_unlock(hdev);
6932
6933 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6934 MGMT_STATUS_SUCCESS, rp, rp_len);
6935
6936 kfree(rp);
6937
6938 return err;
6939}
6940
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006941static u8 calculate_name_len(struct hci_dev *hdev)
6942{
6943 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6944
6945 return append_local_name(hdev, buf, 0);
6946}
6947
6948static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6949 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006950{
Arman Uguray4117ed72015-03-23 15:57:14 -07006951 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006952
Marcel Holtmann31a32482015-11-19 16:16:42 +01006953 if (is_adv_data) {
6954 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6955 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006956 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006957 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006958
Szymon Janc2bb368702016-09-18 12:50:05 +02006959 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006960 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006961 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006962 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006963 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006964
Szymon Janc2bb368702016-09-18 12:50:05 +02006965 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006966 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006967 }
6968
Szymon Janc2bb368702016-09-18 12:50:05 +02006969 return max_len;
6970}
6971
6972static bool flags_managed(u32 adv_flags)
6973{
6974 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6975 MGMT_ADV_FLAG_LIMITED_DISCOV |
6976 MGMT_ADV_FLAG_MANAGED_FLAGS);
6977}
6978
6979static bool tx_power_managed(u32 adv_flags)
6980{
6981 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6982}
6983
6984static bool name_managed(u32 adv_flags)
6985{
6986 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6987}
6988
6989static bool appearance_managed(u32 adv_flags)
6990{
6991 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6992}
6993
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006994static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6995 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006996{
6997 int i, cur_len;
6998 u8 max_len;
6999
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007000 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007001
Arman Uguray4117ed72015-03-23 15:57:14 -07007002 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007003 return false;
7004
Arman Uguray4117ed72015-03-23 15:57:14 -07007005 /* Make sure that the data is correctly formatted. */
7006 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7007 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007008
Szymon Janc9c9db782016-09-18 12:50:06 +02007009 if (data[i + 1] == EIR_FLAGS &&
7010 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007011 return false;
7012
Szymon Janc2bb368702016-09-18 12:50:05 +02007013 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7014 return false;
7015
7016 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7017 return false;
7018
7019 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7020 return false;
7021
7022 if (data[i + 1] == EIR_APPEARANCE &&
7023 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007024 return false;
7025
Arman Uguray24b4f382015-03-23 15:57:12 -07007026 /* If the current field length would exceed the total data
7027 * length, then it's invalid.
7028 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007029 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007030 return false;
7031 }
7032
7033 return true;
7034}
7035
Arman Uguray24b4f382015-03-23 15:57:12 -07007036static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7037 u16 opcode)
7038{
7039 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007040 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007041 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007042 struct adv_info *adv_instance, *n;
7043 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007044
Marcel Holtmann181d6952020-05-06 09:57:47 +02007045 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007046
7047 hci_dev_lock(hdev);
7048
7049 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7050
Florian Grandelfffd38b2015-06-18 03:16:47 +02007051 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7052 if (!adv_instance->pending)
7053 continue;
7054
7055 if (!status) {
7056 adv_instance->pending = false;
7057 continue;
7058 }
7059
7060 instance = adv_instance->instance;
7061
7062 if (hdev->cur_adv_instance == instance)
7063 cancel_adv_timeout(hdev);
7064
7065 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007066 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007067 }
7068
7069 if (!cmd)
7070 goto unlock;
7071
Florian Grandelfffd38b2015-06-18 03:16:47 +02007072 cp = cmd->param;
7073 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007074
7075 if (status)
7076 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7077 mgmt_status(status));
7078 else
7079 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7080 mgmt_status(status), &rp, sizeof(rp));
7081
7082 mgmt_pending_remove(cmd);
7083
7084unlock:
7085 hci_dev_unlock(hdev);
7086}
7087
7088static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7089 void *data, u16 data_len)
7090{
7091 struct mgmt_cp_add_advertising *cp = data;
7092 struct mgmt_rp_add_advertising rp;
7093 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307094 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007095 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007096 u16 timeout, duration;
7097 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7098 u8 schedule_instance = 0;
7099 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007100 int err;
7101 struct mgmt_pending_cmd *cmd;
7102 struct hci_request req;
7103
Marcel Holtmann181d6952020-05-06 09:57:47 +02007104 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007105
7106 status = mgmt_le_support(hdev);
7107 if (status)
7108 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7109 status);
7110
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007111 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7113 MGMT_STATUS_INVALID_PARAMS);
7114
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007115 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7116 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7117 MGMT_STATUS_INVALID_PARAMS);
7118
Arman Uguray24b4f382015-03-23 15:57:12 -07007119 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007120 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007121 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007122
Florian Grandelfffd38b2015-06-18 03:16:47 +02007123 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307124 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007125 */
7126 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307127 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7128 if (flags & ~supported_flags ||
7129 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007130 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7131 MGMT_STATUS_INVALID_PARAMS);
7132
7133 hci_dev_lock(hdev);
7134
Arman Uguray912098a2015-03-23 15:57:15 -07007135 if (timeout && !hdev_is_powered(hdev)) {
7136 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7137 MGMT_STATUS_REJECTED);
7138 goto unlock;
7139 }
7140
Arman Uguray24b4f382015-03-23 15:57:12 -07007141 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007142 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007143 pending_find(MGMT_OP_SET_LE, hdev)) {
7144 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7145 MGMT_STATUS_BUSY);
7146 goto unlock;
7147 }
7148
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007149 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7150 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007151 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007152 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7153 MGMT_STATUS_INVALID_PARAMS);
7154 goto unlock;
7155 }
7156
Florian Grandelfffd38b2015-06-18 03:16:47 +02007157 err = hci_add_adv_instance(hdev, cp->instance, flags,
7158 cp->adv_data_len, cp->data,
7159 cp->scan_rsp_len,
7160 cp->data + cp->adv_data_len,
7161 timeout, duration);
7162 if (err < 0) {
7163 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7164 MGMT_STATUS_FAILED);
7165 goto unlock;
7166 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007167
Florian Grandelfffd38b2015-06-18 03:16:47 +02007168 /* Only trigger an advertising added event if a new instance was
7169 * actually added.
7170 */
7171 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007172 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007173
Florian Grandelfffd38b2015-06-18 03:16:47 +02007174 if (hdev->cur_adv_instance == cp->instance) {
7175 /* If the currently advertised instance is being changed then
7176 * cancel the current advertising and schedule the next
7177 * instance. If there is only one instance then the overridden
7178 * advertising data will be visible right away.
7179 */
7180 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007181
Florian Grandelfffd38b2015-06-18 03:16:47 +02007182 next_instance = hci_get_next_instance(hdev, cp->instance);
7183 if (next_instance)
7184 schedule_instance = next_instance->instance;
7185 } else if (!hdev->adv_instance_timeout) {
7186 /* Immediately advertise the new instance if no other
7187 * instance is currently being advertised.
7188 */
7189 schedule_instance = cp->instance;
7190 }
Arman Uguray912098a2015-03-23 15:57:15 -07007191
Florian Grandelfffd38b2015-06-18 03:16:47 +02007192 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7193 * there is no instance to be advertised then we have no HCI
7194 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007195 */
7196 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007197 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7198 !schedule_instance) {
7199 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007200 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7201 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7202 goto unlock;
7203 }
7204
7205 /* We're good to go, update advertising data, parameters, and start
7206 * advertising.
7207 */
7208 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7209 data_len);
7210 if (!cmd) {
7211 err = -ENOMEM;
7212 goto unlock;
7213 }
7214
7215 hci_req_init(&req, hdev);
7216
Johan Hedbergf2252572015-11-18 12:49:20 +02007217 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007218
Florian Grandelfffd38b2015-06-18 03:16:47 +02007219 if (!err)
7220 err = hci_req_run(&req, add_advertising_complete);
7221
Joseph Hwang72da7b22020-03-10 09:31:50 -07007222 if (err < 0) {
7223 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7224 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007225 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007226 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007227
7228unlock:
7229 hci_dev_unlock(hdev);
7230
7231 return err;
7232}
7233
Arman Ugurayda9293352015-03-23 15:57:13 -07007234static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7235 u16 opcode)
7236{
7237 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007238 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007239 struct mgmt_rp_remove_advertising rp;
7240
Marcel Holtmann181d6952020-05-06 09:57:47 +02007241 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007242
7243 hci_dev_lock(hdev);
7244
7245 /* A failure status here only means that we failed to disable
7246 * advertising. Otherwise, the advertising instance has been removed,
7247 * so report success.
7248 */
7249 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7250 if (!cmd)
7251 goto unlock;
7252
Florian Grandel01948332015-06-18 03:16:48 +02007253 cp = cmd->param;
7254 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007255
7256 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7257 &rp, sizeof(rp));
7258 mgmt_pending_remove(cmd);
7259
7260unlock:
7261 hci_dev_unlock(hdev);
7262}
7263
7264static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7265 void *data, u16 data_len)
7266{
7267 struct mgmt_cp_remove_advertising *cp = data;
7268 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007269 struct mgmt_pending_cmd *cmd;
7270 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007271 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007272
Marcel Holtmann181d6952020-05-06 09:57:47 +02007273 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007274
Arman Ugurayda9293352015-03-23 15:57:13 -07007275 hci_dev_lock(hdev);
7276
Johan Hedberg952497b2015-06-18 21:05:31 +03007277 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007278 err = mgmt_cmd_status(sk, hdev->id,
7279 MGMT_OP_REMOVE_ADVERTISING,
7280 MGMT_STATUS_INVALID_PARAMS);
7281 goto unlock;
7282 }
7283
Arman Ugurayda9293352015-03-23 15:57:13 -07007284 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7285 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7286 pending_find(MGMT_OP_SET_LE, hdev)) {
7287 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7288 MGMT_STATUS_BUSY);
7289 goto unlock;
7290 }
7291
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007292 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007293 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7294 MGMT_STATUS_INVALID_PARAMS);
7295 goto unlock;
7296 }
7297
Florian Grandel01948332015-06-18 03:16:48 +02007298 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007299
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007300 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007301
Florian Grandel01948332015-06-18 03:16:48 +02007302 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007303 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007304
Florian Grandel01948332015-06-18 03:16:48 +02007305 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7306 * flag is set or the device isn't powered then we have no HCI
7307 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007308 */
Florian Grandel01948332015-06-18 03:16:48 +02007309 if (skb_queue_empty(&req.cmd_q) ||
7310 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007311 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307312 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007313 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007314 err = mgmt_cmd_complete(sk, hdev->id,
7315 MGMT_OP_REMOVE_ADVERTISING,
7316 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7317 goto unlock;
7318 }
7319
7320 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7321 data_len);
7322 if (!cmd) {
7323 err = -ENOMEM;
7324 goto unlock;
7325 }
7326
Arman Ugurayda9293352015-03-23 15:57:13 -07007327 err = hci_req_run(&req, remove_advertising_complete);
7328 if (err < 0)
7329 mgmt_pending_remove(cmd);
7330
7331unlock:
7332 hci_dev_unlock(hdev);
7333
7334 return err;
7335}
7336
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007337static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7338 void *data, u16 data_len)
7339{
7340 struct mgmt_cp_get_adv_size_info *cp = data;
7341 struct mgmt_rp_get_adv_size_info rp;
7342 u32 flags, supported_flags;
7343 int err;
7344
Marcel Holtmann181d6952020-05-06 09:57:47 +02007345 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007346
7347 if (!lmp_le_capable(hdev))
7348 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7349 MGMT_STATUS_REJECTED);
7350
7351 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7352 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7353 MGMT_STATUS_INVALID_PARAMS);
7354
7355 flags = __le32_to_cpu(cp->flags);
7356
7357 /* The current implementation only supports a subset of the specified
7358 * flags.
7359 */
7360 supported_flags = get_supported_adv_flags(hdev);
7361 if (flags & ~supported_flags)
7362 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7363 MGMT_STATUS_INVALID_PARAMS);
7364
7365 rp.instance = cp->instance;
7366 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007367 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7368 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007369
7370 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7371 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7372
7373 return err;
7374}
7375
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007376static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007377 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007378 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007379 HCI_MGMT_NO_HDEV |
7380 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007381 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007382 HCI_MGMT_NO_HDEV |
7383 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007384 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007385 HCI_MGMT_NO_HDEV |
7386 HCI_MGMT_UNTRUSTED },
7387 { read_controller_info, MGMT_READ_INFO_SIZE,
7388 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007389 { set_powered, MGMT_SETTING_SIZE },
7390 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7391 { set_connectable, MGMT_SETTING_SIZE },
7392 { set_fast_connectable, MGMT_SETTING_SIZE },
7393 { set_bondable, MGMT_SETTING_SIZE },
7394 { set_link_security, MGMT_SETTING_SIZE },
7395 { set_ssp, MGMT_SETTING_SIZE },
7396 { set_hs, MGMT_SETTING_SIZE },
7397 { set_le, MGMT_SETTING_SIZE },
7398 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7399 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7400 { add_uuid, MGMT_ADD_UUID_SIZE },
7401 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007402 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7403 HCI_MGMT_VAR_LEN },
7404 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7405 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007406 { disconnect, MGMT_DISCONNECT_SIZE },
7407 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7408 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7409 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7410 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7411 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7412 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7413 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7414 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7415 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7416 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7417 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007418 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7419 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7420 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007421 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7422 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7423 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7424 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7425 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7426 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7427 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7428 { set_advertising, MGMT_SETTING_SIZE },
7429 { set_bredr, MGMT_SETTING_SIZE },
7430 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7431 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7432 { set_secure_conn, MGMT_SETTING_SIZE },
7433 { set_debug_keys, MGMT_SETTING_SIZE },
7434 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007435 { load_irks, MGMT_LOAD_IRKS_SIZE,
7436 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007437 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7438 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7439 { add_device, MGMT_ADD_DEVICE_SIZE },
7440 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007441 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7442 HCI_MGMT_VAR_LEN },
7443 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007444 HCI_MGMT_NO_HDEV |
7445 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007446 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007447 HCI_MGMT_UNCONFIGURED |
7448 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007449 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7450 HCI_MGMT_UNCONFIGURED },
7451 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7452 HCI_MGMT_UNCONFIGURED },
7453 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7454 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007455 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007456 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007457 HCI_MGMT_NO_HDEV |
7458 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007459 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007460 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7461 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007462 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007463 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007464 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007465 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7466 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007467 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307468 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307469 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007470 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7471 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007472 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007473 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7474 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007475 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7476 HCI_MGMT_UNTRUSTED |
7477 HCI_MGMT_HDEV_OPTIONAL },
7478 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7479 HCI_MGMT_VAR_LEN |
7480 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007481 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7482 HCI_MGMT_UNTRUSTED },
7483 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7484 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007485 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7486 HCI_MGMT_UNTRUSTED },
7487 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7488 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007489 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7490 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007491 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007492};
7493
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007494void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007495{
Marcel Holtmannced85542015-03-14 19:27:56 -07007496 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007497
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007498 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7499 return;
7500
Marcel Holtmannf9207332015-03-14 19:27:55 -07007501 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007502 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007503 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7504 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7505 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007506 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007507 } else {
7508 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7509 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007510 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007511 }
7512 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007513 case HCI_AMP:
7514 ev.type = 0x02;
7515 break;
7516 default:
7517 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007518 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007519
7520 ev.bus = hdev->bus;
7521
7522 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7523 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007524}
7525
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007526void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007527{
Marcel Holtmannced85542015-03-14 19:27:56 -07007528 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007529 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007530
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007531 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7532 return;
7533
Marcel Holtmannf9207332015-03-14 19:27:55 -07007534 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007535 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007536 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007537
Marcel Holtmannf9207332015-03-14 19:27:55 -07007538 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7539 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7540 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007541 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007542 } else {
7543 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7544 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007545 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007546 }
7547 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007548 case HCI_AMP:
7549 ev.type = 0x02;
7550 break;
7551 default:
7552 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007553 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007554
7555 ev.bus = hdev->bus;
7556
7557 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7558 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007559}
7560
Andre Guedes6046dc32014-02-26 20:21:51 -03007561/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007562static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007563{
7564 struct hci_conn_params *p;
7565
7566 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007567 /* Needed for AUTO_OFF case where might not "really"
7568 * have been powered off.
7569 */
7570 list_del_init(&p->action);
7571
7572 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007573 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007574 case HCI_AUTO_CONN_ALWAYS:
7575 list_add(&p->action, &hdev->pend_le_conns);
7576 break;
7577 case HCI_AUTO_CONN_REPORT:
7578 list_add(&p->action, &hdev->pend_le_reports);
7579 break;
7580 default:
7581 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007582 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007583 }
7584}
7585
Johan Hedberg2ff13892015-11-25 16:15:44 +02007586void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007587{
7588 struct cmd_lookup match = { NULL, hdev };
7589
Marcel Holtmann181d6952020-05-06 09:57:47 +02007590 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007591
Johan Hedberg2ff13892015-11-25 16:15:44 +02007592 hci_dev_lock(hdev);
7593
7594 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007595 restart_le_actions(hdev);
7596 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007597 }
7598
Johan Hedberg229ab392013-03-15 17:06:53 -05007599 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7600
7601 new_settings(hdev, match.sk);
7602
Johan Hedberg229ab392013-03-15 17:06:53 -05007603 if (match.sk)
7604 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007605
7606 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007607}
7608
Johan Hedberg2ff13892015-11-25 16:15:44 +02007609void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007610{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007611 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007612 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007613
Johan Hedberg229ab392013-03-15 17:06:53 -05007614 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007615
7616 /* If the power off is because of hdev unregistration let
7617 * use the appropriate INVALID_INDEX status. Otherwise use
7618 * NOT_POWERED. We cover both scenarios here since later in
7619 * mgmt_index_removed() any hci_conn callbacks will have already
7620 * been triggered, potentially causing misleading DISCONNECTED
7621 * status responses.
7622 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007623 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007624 status = MGMT_STATUS_INVALID_INDEX;
7625 else
7626 status = MGMT_STATUS_NOT_POWERED;
7627
7628 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007629
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007630 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007631 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7632 zero_cod, sizeof(zero_cod),
7633 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007634 ext_info_changed(hdev, NULL);
7635 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007636
Johan Hedberg2ff13892015-11-25 16:15:44 +02007637 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007638
7639 if (match.sk)
7640 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007641}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007642
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007643void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007644{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007645 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007646 u8 status;
7647
Johan Hedberg333ae952015-03-17 13:48:47 +02007648 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007649 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007650 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007651
7652 if (err == -ERFKILL)
7653 status = MGMT_STATUS_RFKILLED;
7654 else
7655 status = MGMT_STATUS_FAILED;
7656
Johan Hedberga69e8372015-03-06 21:08:53 +02007657 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007658
7659 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007660}
7661
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007662void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7663 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007664{
Johan Hedberg86742e12011-11-07 23:13:38 +02007665 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007666
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007667 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007668
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007669 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007670 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007671 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007672 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007673 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007674 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007675
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007676 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007677}
Johan Hedbergf7520542011-01-20 12:34:39 +02007678
Johan Hedbergd7b25452014-05-23 13:19:53 +03007679static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7680{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007681 switch (ltk->type) {
7682 case SMP_LTK:
7683 case SMP_LTK_SLAVE:
7684 if (ltk->authenticated)
7685 return MGMT_LTK_AUTHENTICATED;
7686 return MGMT_LTK_UNAUTHENTICATED;
7687 case SMP_LTK_P256:
7688 if (ltk->authenticated)
7689 return MGMT_LTK_P256_AUTH;
7690 return MGMT_LTK_P256_UNAUTH;
7691 case SMP_LTK_P256_DEBUG:
7692 return MGMT_LTK_P256_DEBUG;
7693 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007694
7695 return MGMT_LTK_UNAUTHENTICATED;
7696}
7697
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007698void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007699{
7700 struct mgmt_ev_new_long_term_key ev;
7701
7702 memset(&ev, 0, sizeof(ev));
7703
Marcel Holtmann5192d302014-02-19 17:11:58 -08007704 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007705 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007706 * to store long term keys. Their addresses will change the
7707 * next time around.
7708 *
7709 * Only when a remote device provides an identity address
7710 * make sure the long term key is stored. If the remote
7711 * identity is known, the long term keys are internally
7712 * mapped to the identity address. So allow static random
7713 * and public addresses here.
7714 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007715 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7716 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7717 ev.store_hint = 0x00;
7718 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007719 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007720
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007721 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007722 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007723 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007724 ev.key.enc_size = key->enc_size;
7725 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007726 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007727
Johan Hedberg2ceba532014-06-16 19:25:16 +03007728 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007729 ev.key.master = 1;
7730
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007731 /* Make sure we copy only the significant bytes based on the
7732 * encryption key size, and set the rest of the value to zeroes.
7733 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007734 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007735 memset(ev.key.val + key->enc_size, 0,
7736 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007737
Marcel Holtmann083368f2013-10-15 14:26:29 -07007738 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007739}
7740
Johan Hedbergcad20c22015-10-12 13:36:19 +02007741void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007742{
7743 struct mgmt_ev_new_irk ev;
7744
7745 memset(&ev, 0, sizeof(ev));
7746
Johan Hedbergcad20c22015-10-12 13:36:19 +02007747 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007748
Johan Hedberg95fbac82014-02-19 15:18:31 +02007749 bacpy(&ev.rpa, &irk->rpa);
7750 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7751 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7752 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7753
7754 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7755}
7756
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007757void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7758 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007759{
7760 struct mgmt_ev_new_csrk ev;
7761
7762 memset(&ev, 0, sizeof(ev));
7763
7764 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007765 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007766 * to store signature resolving keys. Their addresses will change
7767 * the next time around.
7768 *
7769 * Only when a remote device provides an identity address
7770 * make sure the signature resolving key is stored. So allow
7771 * static random and public addresses here.
7772 */
7773 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7774 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7775 ev.store_hint = 0x00;
7776 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007777 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007778
7779 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7780 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007781 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007782 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7783
7784 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7785}
7786
Andre Guedesffb5a8272014-07-01 18:10:11 -03007787void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007788 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7789 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007790{
7791 struct mgmt_ev_new_conn_param ev;
7792
Johan Hedbergc103aea2014-07-02 17:37:34 +03007793 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7794 return;
7795
Andre Guedesffb5a8272014-07-01 18:10:11 -03007796 memset(&ev, 0, sizeof(ev));
7797 bacpy(&ev.addr.bdaddr, bdaddr);
7798 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007799 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007800 ev.min_interval = cpu_to_le16(min_interval);
7801 ev.max_interval = cpu_to_le16(max_interval);
7802 ev.latency = cpu_to_le16(latency);
7803 ev.timeout = cpu_to_le16(timeout);
7804
7805 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7806}
7807
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007808void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7809 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007810{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007811 char buf[512];
7812 struct mgmt_ev_device_connected *ev = (void *) buf;
7813 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007814
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007815 bacpy(&ev->addr.bdaddr, &conn->dst);
7816 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007817
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007818 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007819
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007820 /* We must ensure that the EIR Data fields are ordered and
7821 * unique. Keep it simple for now and avoid the problem by not
7822 * adding any BR/EDR data to the LE adv.
7823 */
7824 if (conn->le_adv_data_len > 0) {
7825 memcpy(&ev->eir[eir_len],
7826 conn->le_adv_data, conn->le_adv_data_len);
7827 eir_len = conn->le_adv_data_len;
7828 } else {
7829 if (name_len > 0)
7830 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7831 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007832
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007833 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007834 eir_len = eir_append_data(ev->eir, eir_len,
7835 EIR_CLASS_OF_DEV,
7836 conn->dev_class, 3);
7837 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007838
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007839 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007840
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007841 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7842 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007843}
7844
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007845static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007846{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007847 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007848
Johan Hedbergf5818c22014-12-05 13:36:02 +02007849 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007850
7851 *sk = cmd->sk;
7852 sock_hold(*sk);
7853
Johan Hedberga664b5b2011-02-19 12:06:02 -03007854 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007855}
7856
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007857static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007858{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007859 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007860 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007861
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007862 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7863
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007864 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007865 mgmt_pending_remove(cmd);
7866}
7867
Johan Hedberg84c61d92014-08-01 11:13:30 +03007868bool mgmt_powering_down(struct hci_dev *hdev)
7869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007870 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007871 struct mgmt_mode *cp;
7872
Johan Hedberg333ae952015-03-17 13:48:47 +02007873 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007874 if (!cmd)
7875 return false;
7876
7877 cp = cmd->param;
7878 if (!cp->val)
7879 return true;
7880
7881 return false;
7882}
7883
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007884void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007885 u8 link_type, u8 addr_type, u8 reason,
7886 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007887{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007888 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007889 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007890
Johan Hedberg84c61d92014-08-01 11:13:30 +03007891 /* The connection is still in hci_conn_hash so test for 1
7892 * instead of 0 to know if this is the last one.
7893 */
7894 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7895 cancel_delayed_work(&hdev->power_off);
7896 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007897 }
7898
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007899 if (!mgmt_connected)
7900 return;
7901
Andre Guedes57eb7762013-10-30 19:01:41 -03007902 if (link_type != ACL_LINK && link_type != LE_LINK)
7903 return;
7904
Johan Hedberg744cf192011-11-08 20:40:14 +02007905 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007906
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007907 bacpy(&ev.addr.bdaddr, bdaddr);
7908 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7909 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007910
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007911 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007912
7913 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007914 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007915
Johan Hedberg124f6e32012-02-09 13:50:12 +02007916 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007917 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007918}
7919
Marcel Holtmann78929242013-10-06 23:55:47 -07007920void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7921 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007922{
Andre Guedes3655bba2013-10-30 19:01:40 -03007923 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7924 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007925 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007926
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007927 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7928 hdev);
7929
Johan Hedberg333ae952015-03-17 13:48:47 +02007930 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007931 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007932 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007933
Andre Guedes3655bba2013-10-30 19:01:40 -03007934 cp = cmd->param;
7935
7936 if (bacmp(bdaddr, &cp->addr.bdaddr))
7937 return;
7938
7939 if (cp->addr.type != bdaddr_type)
7940 return;
7941
Johan Hedbergf5818c22014-12-05 13:36:02 +02007942 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007943 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007944}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007945
Marcel Holtmann445608d2013-10-06 23:55:48 -07007946void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7947 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007948{
7949 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007950
Johan Hedberg84c61d92014-08-01 11:13:30 +03007951 /* The connection is still in hci_conn_hash so test for 1
7952 * instead of 0 to know if this is the last one.
7953 */
7954 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7955 cancel_delayed_work(&hdev->power_off);
7956 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007957 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007958
Johan Hedberg4c659c32011-11-07 23:13:39 +02007959 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007960 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007961 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007962
Marcel Holtmann445608d2013-10-06 23:55:48 -07007963 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007964}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007965
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007966void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007967{
7968 struct mgmt_ev_pin_code_request ev;
7969
Johan Hedbergd8457692012-02-17 14:24:57 +02007970 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007971 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007972 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007973
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007974 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007975}
7976
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007977void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7978 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007979{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007980 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007981
Johan Hedberg333ae952015-03-17 13:48:47 +02007982 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007983 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007984 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007985
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007986 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007987 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007988}
7989
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007990void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7991 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007992{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007993 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007994
Johan Hedberg333ae952015-03-17 13:48:47 +02007995 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007996 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007997 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007998
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007999 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008000 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008001}
Johan Hedberga5c29682011-02-19 12:05:57 -03008002
Johan Hedberg744cf192011-11-08 20:40:14 +02008003int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008004 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008005 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008006{
8007 struct mgmt_ev_user_confirm_request ev;
8008
Marcel Holtmann181d6952020-05-06 09:57:47 +02008009 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008010
Johan Hedberg272d90d2012-02-09 15:26:12 +02008011 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008012 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008013 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008014 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008015
Johan Hedberg744cf192011-11-08 20:40:14 +02008016 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008017 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008018}
8019
Johan Hedberg272d90d2012-02-09 15:26:12 +02008020int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008021 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008022{
8023 struct mgmt_ev_user_passkey_request ev;
8024
Marcel Holtmann181d6952020-05-06 09:57:47 +02008025 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008026
Johan Hedberg272d90d2012-02-09 15:26:12 +02008027 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008028 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008029
8030 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008031 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008032}
8033
Brian Gix0df4c182011-11-16 13:53:13 -08008034static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008035 u8 link_type, u8 addr_type, u8 status,
8036 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008037{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008038 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008039
Johan Hedberg333ae952015-03-17 13:48:47 +02008040 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008041 if (!cmd)
8042 return -ENOENT;
8043
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008044 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008045 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008046
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008047 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008048}
8049
Johan Hedberg744cf192011-11-08 20:40:14 +02008050int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008051 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008052{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008053 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008054 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008055}
8056
Johan Hedberg272d90d2012-02-09 15:26:12 +02008057int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008058 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008059{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008060 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008061 status,
8062 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008063}
Johan Hedberg2a611692011-02-19 12:06:00 -03008064
Brian Gix604086b2011-11-23 08:28:33 -08008065int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008066 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008067{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008068 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008069 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008070}
8071
Johan Hedberg272d90d2012-02-09 15:26:12 +02008072int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008073 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008074{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008075 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008076 status,
8077 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008078}
8079
Johan Hedberg92a25252012-09-06 18:39:26 +03008080int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8081 u8 link_type, u8 addr_type, u32 passkey,
8082 u8 entered)
8083{
8084 struct mgmt_ev_passkey_notify ev;
8085
Marcel Holtmann181d6952020-05-06 09:57:47 +02008086 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008087
8088 bacpy(&ev.addr.bdaddr, bdaddr);
8089 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8090 ev.passkey = __cpu_to_le32(passkey);
8091 ev.entered = entered;
8092
8093 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8094}
8095
Johan Hedberge1e930f2014-09-08 17:09:49 -07008096void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008097{
8098 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008099 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008100 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008101
Johan Hedberge1e930f2014-09-08 17:09:49 -07008102 bacpy(&ev.addr.bdaddr, &conn->dst);
8103 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8104 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008105
Johan Hedberge1e930f2014-09-08 17:09:49 -07008106 cmd = find_pairing(conn);
8107
8108 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8109 cmd ? cmd->sk : NULL);
8110
Johan Hedberga511b352014-12-11 21:45:45 +02008111 if (cmd) {
8112 cmd->cmd_complete(cmd, status);
8113 mgmt_pending_remove(cmd);
8114 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008115}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008116
Marcel Holtmann464996a2013-10-15 14:26:24 -07008117void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008118{
8119 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008120 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008121
8122 if (status) {
8123 u8 mgmt_err = mgmt_status(status);
8124 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008125 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008126 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008127 }
8128
Marcel Holtmann464996a2013-10-15 14:26:24 -07008129 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008130 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008131 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008132 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008133
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008134 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008135 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008136
Johan Hedberg47990ea2012-02-22 11:58:37 +02008137 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008138 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008139
8140 if (match.sk)
8141 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008142}
8143
Johan Hedberg890ea892013-03-15 17:06:52 -05008144static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008145{
Johan Hedberg890ea892013-03-15 17:06:52 -05008146 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008147 struct hci_cp_write_eir cp;
8148
Johan Hedberg976eb202012-10-24 21:12:01 +03008149 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008150 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008151
Johan Hedbergc80da272012-02-22 15:38:48 +02008152 memset(hdev->eir, 0, sizeof(hdev->eir));
8153
Johan Hedbergcacaf522012-02-21 00:52:42 +02008154 memset(&cp, 0, sizeof(cp));
8155
Johan Hedberg890ea892013-03-15 17:06:52 -05008156 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008157}
8158
Marcel Holtmann3e248562013-10-15 14:26:25 -07008159void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008160{
8161 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008162 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008163 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008164
8165 if (status) {
8166 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008167
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008168 if (enable && hci_dev_test_and_clear_flag(hdev,
8169 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008170 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008171 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008172 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008173
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008174 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8175 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008176 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008177 }
8178
8179 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008180 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008181 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008182 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008183 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008184 changed = hci_dev_test_and_clear_flag(hdev,
8185 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008186 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008187 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008188 }
8189
8190 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8191
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008192 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008193 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008194
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008195 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008196 sock_put(match.sk);
8197
Johan Hedberg890ea892013-03-15 17:06:52 -05008198 hci_req_init(&req, hdev);
8199
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008200 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8201 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008202 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8203 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008204 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008205 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008206 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008207 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008208
8209 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008210}
8211
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008212static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008213{
8214 struct cmd_lookup *match = data;
8215
Johan Hedberg90e70452012-02-23 23:09:40 +02008216 if (match->sk == NULL) {
8217 match->sk = cmd->sk;
8218 sock_hold(match->sk);
8219 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008220}
8221
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008222void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8223 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008224{
Johan Hedberg90e70452012-02-23 23:09:40 +02008225 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008226
Johan Hedberg92da6092013-03-15 17:06:55 -05008227 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8228 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8229 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008230
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008231 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008232 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8233 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008234 ext_info_changed(hdev, NULL);
8235 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008236
8237 if (match.sk)
8238 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008239}
8240
Marcel Holtmann7667da32013-10-15 14:26:27 -07008241void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008242{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008243 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008244 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008245
Johan Hedberg13928972013-03-15 17:07:00 -05008246 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008247 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008248
8249 memset(&ev, 0, sizeof(ev));
8250 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008251 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008252
Johan Hedberg333ae952015-03-17 13:48:47 +02008253 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008254 if (!cmd) {
8255 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008256
Johan Hedberg13928972013-03-15 17:07:00 -05008257 /* If this is a HCI command related to powering on the
8258 * HCI dev don't send any mgmt signals.
8259 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008260 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008261 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008262 }
8263
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008264 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8265 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008266 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008267}
Szymon Jancc35938b2011-03-22 13:12:21 +01008268
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008269static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8270{
8271 int i;
8272
8273 for (i = 0; i < uuid_count; i++) {
8274 if (!memcmp(uuid, uuids[i], 16))
8275 return true;
8276 }
8277
8278 return false;
8279}
8280
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008281static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8282{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008283 u16 parsed = 0;
8284
8285 while (parsed < eir_len) {
8286 u8 field_len = eir[0];
8287 u8 uuid[16];
8288 int i;
8289
8290 if (field_len == 0)
8291 break;
8292
8293 if (eir_len - parsed < field_len + 1)
8294 break;
8295
8296 switch (eir[1]) {
8297 case EIR_UUID16_ALL:
8298 case EIR_UUID16_SOME:
8299 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008300 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008301 uuid[13] = eir[i + 3];
8302 uuid[12] = eir[i + 2];
8303 if (has_uuid(uuid, uuid_count, uuids))
8304 return true;
8305 }
8306 break;
8307 case EIR_UUID32_ALL:
8308 case EIR_UUID32_SOME:
8309 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008310 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008311 uuid[15] = eir[i + 5];
8312 uuid[14] = eir[i + 4];
8313 uuid[13] = eir[i + 3];
8314 uuid[12] = eir[i + 2];
8315 if (has_uuid(uuid, uuid_count, uuids))
8316 return true;
8317 }
8318 break;
8319 case EIR_UUID128_ALL:
8320 case EIR_UUID128_SOME:
8321 for (i = 0; i + 17 <= field_len; i += 16) {
8322 memcpy(uuid, eir + i + 2, 16);
8323 if (has_uuid(uuid, uuid_count, uuids))
8324 return true;
8325 }
8326 break;
8327 }
8328
8329 parsed += field_len + 1;
8330 eir += field_len + 1;
8331 }
8332
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008333 return false;
8334}
8335
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008336static void restart_le_scan(struct hci_dev *hdev)
8337{
8338 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008339 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008340 return;
8341
8342 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8343 hdev->discovery.scan_start +
8344 hdev->discovery.scan_duration))
8345 return;
8346
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008347 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008348 DISCOV_LE_RESTART_DELAY);
8349}
8350
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008351static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8352 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8353{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008354 /* If a RSSI threshold has been specified, and
8355 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8356 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8357 * is set, let it through for further processing, as we might need to
8358 * restart the scan.
8359 *
8360 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8361 * the results are also dropped.
8362 */
8363 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8364 (rssi == HCI_RSSI_INVALID ||
8365 (rssi < hdev->discovery.rssi &&
8366 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8367 return false;
8368
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008369 if (hdev->discovery.uuid_count != 0) {
8370 /* If a list of UUIDs is provided in filter, results with no
8371 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008372 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008373 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8374 hdev->discovery.uuids) &&
8375 !eir_has_uuids(scan_rsp, scan_rsp_len,
8376 hdev->discovery.uuid_count,
8377 hdev->discovery.uuids))
8378 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008379 }
8380
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008381 /* If duplicate filtering does not report RSSI changes, then restart
8382 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008383 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008384 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8385 restart_le_scan(hdev);
8386
8387 /* Validate RSSI value against the RSSI threshold once more. */
8388 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8389 rssi < hdev->discovery.rssi)
8390 return false;
8391 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008392
8393 return true;
8394}
8395
Marcel Holtmann901801b2013-10-06 23:55:51 -07008396void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008397 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8398 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008399{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008400 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008401 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008402 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008403
Johan Hedberg75ce2082014-07-02 22:42:01 +03008404 /* Don't send events for a non-kernel initiated discovery. With
8405 * LE one exception is if we have pend_le_reports > 0 in which
8406 * case we're doing passive scanning and want these events.
8407 */
8408 if (!hci_discovery_active(hdev)) {
8409 if (link_type == ACL_LINK)
8410 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03008411 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03008412 return;
8413 }
Andre Guedes12602d02013-04-30 15:29:40 -03008414
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008415 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008416 /* We are using service discovery */
8417 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8418 scan_rsp_len))
8419 return;
8420 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008421
Johan Hedberg78b781c2016-01-05 13:19:32 +02008422 if (hdev->discovery.limited) {
8423 /* Check for limited discoverable bit */
8424 if (dev_class) {
8425 if (!(dev_class[1] & 0x20))
8426 return;
8427 } else {
8428 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8429 if (!flags || !(flags[0] & LE_AD_LIMITED))
8430 return;
8431 }
8432 }
8433
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008434 /* Make sure that the buffer is big enough. The 5 extra bytes
8435 * are for the potential CoD field.
8436 */
8437 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008438 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008439
Johan Hedberg1dc06092012-01-15 21:01:23 +02008440 memset(buf, 0, sizeof(buf));
8441
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008442 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8443 * RSSI value was reported as 0 when not available. This behavior
8444 * is kept when using device discovery. This is required for full
8445 * backwards compatibility with the API.
8446 *
8447 * However when using service discovery, the value 127 will be
8448 * returned when the RSSI is not available.
8449 */
Szymon Janc91200e92015-01-22 16:57:05 +01008450 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8451 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008452 rssi = 0;
8453
Johan Hedberg841c5642014-07-07 12:45:54 +03008454 bacpy(&ev->addr.bdaddr, bdaddr);
8455 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008456 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008457 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008458
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008459 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008460 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008461 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008462
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008463 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8464 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008465 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008466 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008467
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008468 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008469 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008470 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008471
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008472 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8473 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008474
Marcel Holtmann901801b2013-10-06 23:55:51 -07008475 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008476}
Johan Hedberga88a9652011-03-30 13:18:12 +03008477
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008478void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8479 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008480{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008481 struct mgmt_ev_device_found *ev;
8482 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8483 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008484
Johan Hedbergb644ba32012-01-17 21:48:47 +02008485 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008486
Johan Hedbergb644ba32012-01-17 21:48:47 +02008487 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008488
Johan Hedbergb644ba32012-01-17 21:48:47 +02008489 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008490 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008491 ev->rssi = rssi;
8492
8493 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008494 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008495
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008496 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008497
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008498 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008499}
Johan Hedberg314b2382011-04-27 10:29:57 -04008500
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008501void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008502{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008503 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008504
Marcel Holtmann181d6952020-05-06 09:57:47 +02008505 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008506
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008507 memset(&ev, 0, sizeof(ev));
8508 ev.type = hdev->discovery.type;
8509 ev.discovering = discovering;
8510
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008511 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008512}
Antti Julku5e762442011-08-25 16:48:02 +03008513
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008514static struct hci_mgmt_chan chan = {
8515 .channel = HCI_CHANNEL_CONTROL,
8516 .handler_count = ARRAY_SIZE(mgmt_handlers),
8517 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008518 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008519};
8520
8521int mgmt_init(void)
8522{
8523 return hci_mgmt_chan_register(&chan);
8524}
8525
8526void mgmt_exit(void)
8527{
8528 hci_mgmt_chan_unregister(&chan);
8529}