blob: d29da80e38fec4a490c4d092e0dce29d2eaddf51 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Alain Michaud17896402020-06-11 02:01:57 +000039#include "mgmt_config.h"
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +020040#include "msft.h"
Johan Hedberg03811012010-12-08 00:21:06 +020041
Johan Hedberg2da9c552012-02-17 14:39:28 +020042#define MGMT_VERSION 1
Marcel Holtmann3679fe72020-04-03 21:44:06 +020043#define MGMT_REVISION 17
Johan Hedberg02d98122010-12-13 21:07:04 +020044
Johan Hedberge70bb2e2012-02-13 16:59:33 +020045static const u16 mgmt_commands[] = {
46 MGMT_OP_READ_INDEX_LIST,
47 MGMT_OP_READ_INFO,
48 MGMT_OP_SET_POWERED,
49 MGMT_OP_SET_DISCOVERABLE,
50 MGMT_OP_SET_CONNECTABLE,
51 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030052 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020053 MGMT_OP_SET_LINK_SECURITY,
54 MGMT_OP_SET_SSP,
55 MGMT_OP_SET_HS,
56 MGMT_OP_SET_LE,
57 MGMT_OP_SET_DEV_CLASS,
58 MGMT_OP_SET_LOCAL_NAME,
59 MGMT_OP_ADD_UUID,
60 MGMT_OP_REMOVE_UUID,
61 MGMT_OP_LOAD_LINK_KEYS,
62 MGMT_OP_LOAD_LONG_TERM_KEYS,
63 MGMT_OP_DISCONNECT,
64 MGMT_OP_GET_CONNECTIONS,
65 MGMT_OP_PIN_CODE_REPLY,
66 MGMT_OP_PIN_CODE_NEG_REPLY,
67 MGMT_OP_SET_IO_CAPABILITY,
68 MGMT_OP_PAIR_DEVICE,
69 MGMT_OP_CANCEL_PAIR_DEVICE,
70 MGMT_OP_UNPAIR_DEVICE,
71 MGMT_OP_USER_CONFIRM_REPLY,
72 MGMT_OP_USER_CONFIRM_NEG_REPLY,
73 MGMT_OP_USER_PASSKEY_REPLY,
74 MGMT_OP_USER_PASSKEY_NEG_REPLY,
75 MGMT_OP_READ_LOCAL_OOB_DATA,
76 MGMT_OP_ADD_REMOTE_OOB_DATA,
77 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
78 MGMT_OP_START_DISCOVERY,
79 MGMT_OP_STOP_DISCOVERY,
80 MGMT_OP_CONFIRM_NAME,
81 MGMT_OP_BLOCK_DEVICE,
82 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070083 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030084 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030085 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070086 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070087 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080088 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080089 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020090 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020091 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020092 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030093 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020094 MGMT_OP_ADD_DEVICE,
95 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030096 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020097 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020098 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020099 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +0200100 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100101 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700102 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700103 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700104 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700105 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700106 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100107 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200108 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200109 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200110 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000111 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000112 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200113 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200114 MGMT_OP_READ_EXP_FEATURES_INFO,
115 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000116 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
117 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200118 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
119 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200120 MGMT_OP_GET_DEVICE_FLAGS,
121 MGMT_OP_SET_DEVICE_FLAGS,
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +0200122 MGMT_OP_READ_ADV_MONITOR_FEATURES,
Miao-chen Choub1395532020-06-17 16:39:14 +0200123 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
Miao-chen Choubd2fbc62020-06-17 16:39:15 +0200124 MGMT_OP_REMOVE_ADV_MONITOR,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200125};
126
127static const u16 mgmt_events[] = {
128 MGMT_EV_CONTROLLER_ERROR,
129 MGMT_EV_INDEX_ADDED,
130 MGMT_EV_INDEX_REMOVED,
131 MGMT_EV_NEW_SETTINGS,
132 MGMT_EV_CLASS_OF_DEV_CHANGED,
133 MGMT_EV_LOCAL_NAME_CHANGED,
134 MGMT_EV_NEW_LINK_KEY,
135 MGMT_EV_NEW_LONG_TERM_KEY,
136 MGMT_EV_DEVICE_CONNECTED,
137 MGMT_EV_DEVICE_DISCONNECTED,
138 MGMT_EV_CONNECT_FAILED,
139 MGMT_EV_PIN_CODE_REQUEST,
140 MGMT_EV_USER_CONFIRM_REQUEST,
141 MGMT_EV_USER_PASSKEY_REQUEST,
142 MGMT_EV_AUTH_FAILED,
143 MGMT_EV_DEVICE_FOUND,
144 MGMT_EV_DISCOVERING,
145 MGMT_EV_DEVICE_BLOCKED,
146 MGMT_EV_DEVICE_UNBLOCKED,
147 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300148 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800149 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700150 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200151 MGMT_EV_DEVICE_ADDED,
152 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300153 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200154 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200155 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200156 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700157 MGMT_EV_EXT_INDEX_ADDED,
158 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700159 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700160 MGMT_EV_ADVERTISING_ADDED,
161 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200162 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200163 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200164 MGMT_EV_EXP_FEATURE_CHANGED,
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +0200165 MGMT_EV_DEVICE_FLAGS_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200166};
167
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700168static const u16 mgmt_untrusted_commands[] = {
169 MGMT_OP_READ_INDEX_LIST,
170 MGMT_OP_READ_INFO,
171 MGMT_OP_READ_UNCONF_INDEX_LIST,
172 MGMT_OP_READ_CONFIG_INFO,
173 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200174 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200175 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200176 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000177 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200178 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700179};
180
181static const u16 mgmt_untrusted_events[] = {
182 MGMT_EV_INDEX_ADDED,
183 MGMT_EV_INDEX_REMOVED,
184 MGMT_EV_NEW_SETTINGS,
185 MGMT_EV_CLASS_OF_DEV_CHANGED,
186 MGMT_EV_LOCAL_NAME_CHANGED,
187 MGMT_EV_UNCONF_INDEX_ADDED,
188 MGMT_EV_UNCONF_INDEX_REMOVED,
189 MGMT_EV_NEW_CONFIG_OPTIONS,
190 MGMT_EV_EXT_INDEX_ADDED,
191 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200192 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200193 MGMT_EV_EXP_FEATURE_CHANGED,
Miao-chen Choub52729f2020-06-17 16:39:16 +0200194 MGMT_EV_ADV_MONITOR_ADDED,
Miao-chen Choucdde92e2020-06-17 16:39:17 +0200195 MGMT_EV_ADV_MONITOR_REMOVED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700196};
197
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800198#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200199
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200200#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
201 "\x00\x00\x00\x00\x00\x00\x00\x00"
202
Johan Hedbergca69b792011-11-11 18:10:00 +0200203/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000204static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200205 MGMT_STATUS_SUCCESS,
206 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
207 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
208 MGMT_STATUS_FAILED, /* Hardware Failure */
209 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
210 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200211 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200212 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
213 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
214 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
215 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
216 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
217 MGMT_STATUS_BUSY, /* Command Disallowed */
218 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
219 MGMT_STATUS_REJECTED, /* Rejected Security */
220 MGMT_STATUS_REJECTED, /* Rejected Personal */
221 MGMT_STATUS_TIMEOUT, /* Host Timeout */
222 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
223 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
224 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
225 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
226 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
227 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
228 MGMT_STATUS_BUSY, /* Repeated Attempts */
229 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
230 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
231 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
232 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
233 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
234 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
235 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
236 MGMT_STATUS_FAILED, /* Unspecified Error */
237 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
238 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
239 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
240 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
241 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
242 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
243 MGMT_STATUS_FAILED, /* Unit Link Key Used */
244 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
245 MGMT_STATUS_TIMEOUT, /* Instant Passed */
246 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
247 MGMT_STATUS_FAILED, /* Transaction Collision */
248 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
249 MGMT_STATUS_REJECTED, /* QoS Rejected */
250 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
251 MGMT_STATUS_REJECTED, /* Insufficient Security */
252 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
253 MGMT_STATUS_BUSY, /* Role Switch Pending */
254 MGMT_STATUS_FAILED, /* Slot Violation */
255 MGMT_STATUS_FAILED, /* Role Switch Failed */
256 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
257 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
258 MGMT_STATUS_BUSY, /* Host Busy Pairing */
259 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
260 MGMT_STATUS_BUSY, /* Controller Busy */
261 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
262 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
263 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
264 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
265 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
266};
267
268static u8 mgmt_status(u8 hci_status)
269{
270 if (hci_status < ARRAY_SIZE(mgmt_status_table))
271 return mgmt_status_table[hci_status];
272
273 return MGMT_STATUS_FAILED;
274}
275
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700276static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
277 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700278{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700279 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
280 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700281}
282
Marcel Holtmann72000df2015-03-16 16:11:21 -0700283static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
284 u16 len, int flag, struct sock *skip_sk)
285{
286 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
287 flag, skip_sk);
288}
289
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200290static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
291 struct sock *skip_sk)
292{
293 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700294 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200295}
296
Johan Hedberg85813a72015-10-21 18:02:59 +0300297static u8 le_addr_type(u8 mgmt_addr_type)
298{
299 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
300 return ADDR_LE_DEV_PUBLIC;
301 else
302 return ADDR_LE_DEV_RANDOM;
303}
304
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200305void mgmt_fill_version_info(void *ver)
306{
307 struct mgmt_rp_read_version *rp = ver;
308
309 rp->version = MGMT_VERSION;
310 rp->revision = cpu_to_le16(MGMT_REVISION);
311}
312
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
314 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200315{
316 struct mgmt_rp_read_version rp;
317
Marcel Holtmann181d6952020-05-06 09:57:47 +0200318 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200319
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200320 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200321
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200322 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
323 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200324}
325
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300326static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
327 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328{
329 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700330 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200331 size_t rp_size;
332 int i, err;
333
Marcel Holtmann181d6952020-05-06 09:57:47 +0200334 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200335
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700336 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
337 num_commands = ARRAY_SIZE(mgmt_commands);
338 num_events = ARRAY_SIZE(mgmt_events);
339 } else {
340 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
341 num_events = ARRAY_SIZE(mgmt_untrusted_events);
342 }
343
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200344 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
345
346 rp = kmalloc(rp_size, GFP_KERNEL);
347 if (!rp)
348 return -ENOMEM;
349
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700350 rp->num_commands = cpu_to_le16(num_commands);
351 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200352
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700353 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
354 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200355
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700356 for (i = 0; i < num_commands; i++, opcode++)
357 put_unaligned_le16(mgmt_commands[i], opcode);
358
359 for (i = 0; i < num_events; i++, opcode++)
360 put_unaligned_le16(mgmt_events[i], opcode);
361 } else {
362 __le16 *opcode = rp->opcodes;
363
364 for (i = 0; i < num_commands; i++, opcode++)
365 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
366
367 for (i = 0; i < num_events; i++, opcode++)
368 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
369 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200370
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200371 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
372 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200373 kfree(rp);
374
375 return err;
376}
377
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300378static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
379 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200381 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200382 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200383 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200384 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300385 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200386
Marcel Holtmann181d6952020-05-06 09:57:47 +0200387 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200388
389 read_lock(&hci_dev_list_lock);
390
391 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300392 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200393 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700394 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700395 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 }
397
Johan Hedberga38528f2011-01-22 06:46:43 +0200398 rp_len = sizeof(*rp) + (2 * count);
399 rp = kmalloc(rp_len, GFP_ATOMIC);
400 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100401 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100403 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404
Johan Hedberg476e44c2012-10-19 20:10:46 +0300405 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200406 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700407 if (hci_dev_test_flag(d, HCI_SETUP) ||
408 hci_dev_test_flag(d, HCI_CONFIG) ||
409 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200410 continue;
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412 /* Devices marked as raw-only are neither configured
413 * nor unconfigured controllers.
414 */
415 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700416 continue;
417
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200418 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700419 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700420 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200421 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700422 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200423 }
424
Johan Hedberg476e44c2012-10-19 20:10:46 +0300425 rp->num_controllers = cpu_to_le16(count);
426 rp_len = sizeof(*rp) + (2 * count);
427
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200428 read_unlock(&hci_dev_list_lock);
429
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200430 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
431 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200432
Johan Hedberga38528f2011-01-22 06:46:43 +0200433 kfree(rp);
434
435 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200436}
437
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
439 void *data, u16 data_len)
440{
441 struct mgmt_rp_read_unconf_index_list *rp;
442 struct hci_dev *d;
443 size_t rp_len;
444 u16 count;
445 int err;
446
Marcel Holtmann181d6952020-05-06 09:57:47 +0200447 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448
449 read_lock(&hci_dev_list_lock);
450
451 count = 0;
452 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200453 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700454 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200455 count++;
456 }
457
458 rp_len = sizeof(*rp) + (2 * count);
459 rp = kmalloc(rp_len, GFP_ATOMIC);
460 if (!rp) {
461 read_unlock(&hci_dev_list_lock);
462 return -ENOMEM;
463 }
464
465 count = 0;
466 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700467 if (hci_dev_test_flag(d, HCI_SETUP) ||
468 hci_dev_test_flag(d, HCI_CONFIG) ||
469 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200470 continue;
471
472 /* Devices marked as raw-only are neither configured
473 * nor unconfigured controllers.
474 */
475 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
476 continue;
477
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200478 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700479 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200480 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200481 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200482 }
483 }
484
485 rp->num_controllers = cpu_to_le16(count);
486 rp_len = sizeof(*rp) + (2 * count);
487
488 read_unlock(&hci_dev_list_lock);
489
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200490 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
491 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200492
493 kfree(rp);
494
495 return err;
496}
497
Marcel Holtmann96f14742015-03-14 19:27:57 -0700498static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
499 void *data, u16 data_len)
500{
501 struct mgmt_rp_read_ext_index_list *rp;
502 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700503 u16 count;
504 int err;
505
Marcel Holtmann181d6952020-05-06 09:57:47 +0200506 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700507
508 read_lock(&hci_dev_list_lock);
509
510 count = 0;
511 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200512 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700513 count++;
514 }
515
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600516 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700517 if (!rp) {
518 read_unlock(&hci_dev_list_lock);
519 return -ENOMEM;
520 }
521
522 count = 0;
523 list_for_each_entry(d, &hci_dev_list, list) {
524 if (hci_dev_test_flag(d, HCI_SETUP) ||
525 hci_dev_test_flag(d, HCI_CONFIG) ||
526 hci_dev_test_flag(d, HCI_USER_CHANNEL))
527 continue;
528
529 /* Devices marked as raw-only are neither configured
530 * nor unconfigured controllers.
531 */
532 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
533 continue;
534
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200535 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700536 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
537 rp->entry[count].type = 0x01;
538 else
539 rp->entry[count].type = 0x00;
540 } else if (d->dev_type == HCI_AMP) {
541 rp->entry[count].type = 0x02;
542 } else {
543 continue;
544 }
545
546 rp->entry[count].bus = d->bus;
547 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200548 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700549 }
550
551 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700552
553 read_unlock(&hci_dev_list_lock);
554
555 /* If this command is called at least once, then all the
556 * default index and unconfigured index events are disabled
557 * and from now on only extended index events are used.
558 */
559 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
560 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
561 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
562
563 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600564 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
565 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700566
567 kfree(rp);
568
569 return err;
570}
571
Marcel Holtmanndbece372014-07-04 18:11:55 +0200572static bool is_configured(struct hci_dev *hdev)
573{
574 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700575 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200576 return false;
577
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800578 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
579 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200580 !bacmp(&hdev->public_addr, BDADDR_ANY))
581 return false;
582
583 return true;
584}
585
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200586static __le32 get_missing_options(struct hci_dev *hdev)
587{
588 u32 options = 0;
589
Marcel Holtmanndbece372014-07-04 18:11:55 +0200590 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700591 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200592 options |= MGMT_OPTION_EXTERNAL_CONFIG;
593
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800594 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
595 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200596 !bacmp(&hdev->public_addr, BDADDR_ANY))
597 options |= MGMT_OPTION_PUBLIC_ADDRESS;
598
599 return cpu_to_le32(options);
600}
601
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200602static int new_options(struct hci_dev *hdev, struct sock *skip)
603{
604 __le32 options = get_missing_options(hdev);
605
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200606 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
607 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200608}
609
Marcel Holtmanndbece372014-07-04 18:11:55 +0200610static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
611{
612 __le32 options = get_missing_options(hdev);
613
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200614 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
615 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200616}
617
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200618static int read_config_info(struct sock *sk, struct hci_dev *hdev,
619 void *data, u16 data_len)
620{
621 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200622 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200623
Marcel Holtmann181d6952020-05-06 09:57:47 +0200624 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200625
626 hci_dev_lock(hdev);
627
628 memset(&rp, 0, sizeof(rp));
629 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200630
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200631 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
632 options |= MGMT_OPTION_EXTERNAL_CONFIG;
633
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200634 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200635 options |= MGMT_OPTION_PUBLIC_ADDRESS;
636
637 rp.supported_options = cpu_to_le32(options);
638 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200639
640 hci_dev_unlock(hdev);
641
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200642 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
643 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200644}
645
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530646static u32 get_supported_phys(struct hci_dev *hdev)
647{
648 u32 supported_phys = 0;
649
650 if (lmp_bredr_capable(hdev)) {
651 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
652
653 if (hdev->features[0][0] & LMP_3SLOT)
654 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
655
656 if (hdev->features[0][0] & LMP_5SLOT)
657 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
658
659 if (lmp_edr_2m_capable(hdev)) {
660 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
661
662 if (lmp_edr_3slot_capable(hdev))
663 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
664
665 if (lmp_edr_5slot_capable(hdev))
666 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
667
668 if (lmp_edr_3m_capable(hdev)) {
669 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
670
671 if (lmp_edr_3slot_capable(hdev))
672 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
673
674 if (lmp_edr_5slot_capable(hdev))
675 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
676 }
677 }
678 }
679
680 if (lmp_le_capable(hdev)) {
681 supported_phys |= MGMT_PHY_LE_1M_TX;
682 supported_phys |= MGMT_PHY_LE_1M_RX;
683
684 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
685 supported_phys |= MGMT_PHY_LE_2M_TX;
686 supported_phys |= MGMT_PHY_LE_2M_RX;
687 }
688
689 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
690 supported_phys |= MGMT_PHY_LE_CODED_TX;
691 supported_phys |= MGMT_PHY_LE_CODED_RX;
692 }
693 }
694
695 return supported_phys;
696}
697
698static u32 get_selected_phys(struct hci_dev *hdev)
699{
700 u32 selected_phys = 0;
701
702 if (lmp_bredr_capable(hdev)) {
703 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
704
705 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
706 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
707
708 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
709 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
710
711 if (lmp_edr_2m_capable(hdev)) {
712 if (!(hdev->pkt_type & HCI_2DH1))
713 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
714
715 if (lmp_edr_3slot_capable(hdev) &&
716 !(hdev->pkt_type & HCI_2DH3))
717 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
718
719 if (lmp_edr_5slot_capable(hdev) &&
720 !(hdev->pkt_type & HCI_2DH5))
721 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
722
723 if (lmp_edr_3m_capable(hdev)) {
724 if (!(hdev->pkt_type & HCI_3DH1))
725 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
726
727 if (lmp_edr_3slot_capable(hdev) &&
728 !(hdev->pkt_type & HCI_3DH3))
729 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
730
731 if (lmp_edr_5slot_capable(hdev) &&
732 !(hdev->pkt_type & HCI_3DH5))
733 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
734 }
735 }
736 }
737
738 if (lmp_le_capable(hdev)) {
739 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
740 selected_phys |= MGMT_PHY_LE_1M_TX;
741
742 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
743 selected_phys |= MGMT_PHY_LE_1M_RX;
744
745 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
746 selected_phys |= MGMT_PHY_LE_2M_TX;
747
748 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
749 selected_phys |= MGMT_PHY_LE_2M_RX;
750
751 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
752 selected_phys |= MGMT_PHY_LE_CODED_TX;
753
754 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
755 selected_phys |= MGMT_PHY_LE_CODED_RX;
756 }
757
758 return selected_phys;
759}
760
761static u32 get_configurable_phys(struct hci_dev *hdev)
762{
763 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
764 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
765}
766
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200768{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200769 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200770
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300772 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800773 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300774 settings |= MGMT_SETTING_CONNECTABLE;
775 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Andre Guedesed3fa312012-07-24 15:03:46 -0300777 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500778 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
779 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200780 settings |= MGMT_SETTING_BREDR;
781 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700782
783 if (lmp_ssp_capable(hdev)) {
784 settings |= MGMT_SETTING_SSP;
785 settings |= MGMT_SETTING_HS;
786 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800787
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800788 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800789 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000790
Alain Michaud00bce3f2020-03-05 16:14:59 +0000791 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000792 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000793 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700794 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100795
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300796 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200797 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300798 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300799 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200800 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800801 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300802 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200803
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200804 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
805 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200806 settings |= MGMT_SETTING_CONFIGURATION;
807
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530808 settings |= MGMT_SETTING_PHY_CONFIGURATION;
809
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200810 return settings;
811}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200812
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200813static u32 get_current_settings(struct hci_dev *hdev)
814{
815 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200816
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200817 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100818 settings |= MGMT_SETTING_POWERED;
819
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700820 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200821 settings |= MGMT_SETTING_CONNECTABLE;
822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700823 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500824 settings |= MGMT_SETTING_FAST_CONNECTABLE;
825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700826 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827 settings |= MGMT_SETTING_DISCOVERABLE;
828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700829 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300830 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700832 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 settings |= MGMT_SETTING_BREDR;
834
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700835 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200836 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200837
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700838 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200839 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200840
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700841 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200842 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200843
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700844 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200845 settings |= MGMT_SETTING_HS;
846
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700847 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300848 settings |= MGMT_SETTING_ADVERTISING;
849
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700850 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800851 settings |= MGMT_SETTING_SECURE_CONN;
852
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700853 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800854 settings |= MGMT_SETTING_DEBUG_KEYS;
855
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700856 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200857 settings |= MGMT_SETTING_PRIVACY;
858
Marcel Holtmann93690c22015-03-06 10:11:21 -0800859 /* The current setting for static address has two purposes. The
860 * first is to indicate if the static address will be used and
861 * the second is to indicate if it is actually set.
862 *
863 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700864 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800865 * address is actually used decides if the flag is set or not.
866 *
867 * For single mode LE only controllers and dual-mode controllers
868 * with BR/EDR disabled, the existence of the static address will
869 * be evaluated.
870 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700871 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700872 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800873 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
874 if (bacmp(&hdev->static_addr, BDADDR_ANY))
875 settings |= MGMT_SETTING_STATIC_ADDRESS;
876 }
877
Alain Michaud00bce3f2020-03-05 16:14:59 +0000878 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
879 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
880
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200881 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200882}
883
Johan Hedberg333ae952015-03-17 13:48:47 +0200884static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
885{
886 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
887}
888
Johan Hedberg333ae952015-03-17 13:48:47 +0200889static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
890 struct hci_dev *hdev,
891 const void *data)
892{
893 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
894}
895
Johan Hedbergf2252572015-11-18 12:49:20 +0200896u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300897{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200898 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300899
900 /* If there's a pending mgmt command the flags will not yet have
901 * their final values, so check for this first.
902 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200903 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300904 if (cmd) {
905 struct mgmt_mode *cp = cmd->param;
906 if (cp->val == 0x01)
907 return LE_AD_GENERAL;
908 else if (cp->val == 0x02)
909 return LE_AD_LIMITED;
910 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700911 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300912 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700913 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300914 return LE_AD_GENERAL;
915 }
916
917 return 0;
918}
919
Johan Hedbergf2252572015-11-18 12:49:20 +0200920bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700921{
922 struct mgmt_pending_cmd *cmd;
923
924 /* If there's a pending mgmt command the flag will not yet have
925 * it's final value, so check for this first.
926 */
927 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
928 if (cmd) {
929 struct mgmt_mode *cp = cmd->param;
930
931 return cp->val;
932 }
933
934 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
935}
936
Johan Hedberg7d785252011-12-15 00:47:39 +0200937static void service_cache_off(struct work_struct *work)
938{
939 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300940 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500941 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200942
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700943 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200944 return;
945
Johan Hedberg890ea892013-03-15 17:06:52 -0500946 hci_req_init(&req, hdev);
947
Johan Hedberg7d785252011-12-15 00:47:39 +0200948 hci_dev_lock(hdev);
949
Johan Hedbergb1a89172015-11-25 16:15:42 +0200950 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200951 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200952
953 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500954
955 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200956}
957
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200958static void rpa_expired(struct work_struct *work)
959{
960 struct hci_dev *hdev = container_of(work, struct hci_dev,
961 rpa_expired.work);
962 struct hci_request req;
963
Marcel Holtmann181d6952020-05-06 09:57:47 +0200964 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200965
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700966 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200967
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700968 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200969 return;
970
971 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200972 * controller happens in the hci_req_enable_advertising()
973 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200974 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200975 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530976 if (ext_adv_capable(hdev))
977 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
978 else
979 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200980 hci_req_run(&req, NULL);
981}
982
Johan Hedberg6a919082012-02-28 06:17:26 +0200983static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200984{
Marcel Holtmann238be782015-03-13 02:11:06 -0700985 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200986 return;
987
Johan Hedberg4f87da82012-03-02 19:55:56 +0200988 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200989 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200990
Johan Hedberg4f87da82012-03-02 19:55:56 +0200991 /* Non-mgmt controlled devices get this bit set
992 * implicitly so that pairing works for them, however
993 * for mgmt we require user-space to explicitly enable
994 * it
995 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700996 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200997}
998
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200999static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001000 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001001{
1002 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001003
Marcel Holtmann181d6952020-05-06 09:57:47 +02001004 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +02001005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001006 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001007
Johan Hedberg03811012010-12-08 00:21:06 +02001008 memset(&rp, 0, sizeof(rp));
1009
Johan Hedberg03811012010-12-08 00:21:06 +02001010 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001011
1012 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001013 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001014
1015 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1016 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1017
1018 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001019
1020 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001021 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001024
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001025 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1026 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001027}
1028
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001029static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1030{
1031 u16 eir_len = 0;
1032 size_t name_len;
1033
1034 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1035 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1036 hdev->dev_class, 3);
1037
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001038 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1039 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1040 hdev->appearance);
1041
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001042 name_len = strlen(hdev->dev_name);
1043 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1044 hdev->dev_name, name_len);
1045
1046 name_len = strlen(hdev->short_name);
1047 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1048 hdev->short_name, name_len);
1049
1050 return eir_len;
1051}
1052
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001053static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1054 void *data, u16 data_len)
1055{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001056 char buf[512];
1057 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001058 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001059
Marcel Holtmann181d6952020-05-06 09:57:47 +02001060 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001061
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001062 memset(&buf, 0, sizeof(buf));
1063
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001064 hci_dev_lock(hdev);
1065
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001066 bacpy(&rp->bdaddr, &hdev->bdaddr);
1067
1068 rp->version = hdev->hci_ver;
1069 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1070
1071 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1072 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001073
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001074
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001075 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001076 rp->eir_len = cpu_to_le16(eir_len);
1077
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001078 hci_dev_unlock(hdev);
1079
1080 /* If this command is called at least once, then the events
1081 * for class of device and local name changes are disabled
1082 * and only the new extended controller information event
1083 * is used.
1084 */
1085 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1086 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1087 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1088
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001089 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1090 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001091}
1092
1093static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1094{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001095 char buf[512];
1096 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1097 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001098
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001099 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001100
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001101 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1102 ev->eir_len = cpu_to_le16(eir_len);
1103
1104 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1105 sizeof(*ev) + eir_len,
1106 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001107}
1108
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001109static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001110{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001111 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001112
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001113 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1114 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001115}
1116
Marcel Holtmann1904a852015-01-11 13:50:44 -08001117static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001118{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001119 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001120
Johan Hedberga3172b72014-02-28 09:33:44 +02001121 if (hci_conn_count(hdev) == 0) {
1122 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001123 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001124 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001125}
1126
Johan Hedbergf2252572015-11-18 12:49:20 +02001127void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001128{
1129 struct mgmt_ev_advertising_added ev;
1130
1131 ev.instance = instance;
1132
1133 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1134}
1135
Johan Hedbergf2252572015-11-18 12:49:20 +02001136void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1137 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001138{
1139 struct mgmt_ev_advertising_removed ev;
1140
1141 ev.instance = instance;
1142
1143 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1144}
1145
Florian Grandel7816b822015-06-18 03:16:45 +02001146static void cancel_adv_timeout(struct hci_dev *hdev)
1147{
1148 if (hdev->adv_instance_timeout) {
1149 hdev->adv_instance_timeout = 0;
1150 cancel_delayed_work(&hdev->adv_instance_expire);
1151 }
1152}
1153
Johan Hedberg8b064a32014-02-24 14:52:22 +02001154static int clean_up_hci_state(struct hci_dev *hdev)
1155{
1156 struct hci_request req;
1157 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001158 bool discov_stopped;
1159 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001160
1161 hci_req_init(&req, hdev);
1162
1163 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1164 test_bit(HCI_PSCAN, &hdev->flags)) {
1165 u8 scan = 0x00;
1166 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1167 }
1168
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001169 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001170
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001171 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001172 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001173
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001174 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001175
1176 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001177 /* 0x15 == Terminated due to Power Off */
1178 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001179 }
1180
Johan Hedberg23a48092014-07-08 16:05:06 +03001181 err = hci_req_run(&req, clean_up_hci_complete);
1182 if (!err && discov_stopped)
1183 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1184
1185 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186}
1187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001189 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001191 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001192 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001193 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194
Marcel Holtmann181d6952020-05-06 09:57:47 +02001195 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedberga7e80f22013-01-09 16:05:19 +02001197 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001198 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1199 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
Johan Hedberg333ae952015-03-17 13:48:47 +02001203 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001204 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1205 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001206 goto failed;
1207 }
1208
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001209 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001210 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 goto failed;
1212 }
1213
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1215 if (!cmd) {
1216 err = -ENOMEM;
1217 goto failed;
1218 }
1219
Johan Hedberg8b064a32014-02-24 14:52:22 +02001220 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001221 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001222 err = 0;
1223 } else {
1224 /* Disconnect connections, stop scans, etc */
1225 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001226 if (!err)
1227 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1228 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001229
Johan Hedberg8b064a32014-02-24 14:52:22 +02001230 /* ENODATA means there were no HCI commands queued */
1231 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001232 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001233 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1234 err = 0;
1235 }
1236 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001237
1238failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001239 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001240 return err;
1241}
1242
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001243static int new_settings(struct hci_dev *hdev, struct sock *skip)
1244{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001245 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001246
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001247 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1248 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001249}
1250
Johan Hedberg91a668b2014-07-09 13:28:26 +03001251int mgmt_new_settings(struct hci_dev *hdev)
1252{
1253 return new_settings(hdev, NULL);
1254}
1255
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001256struct cmd_lookup {
1257 struct sock *sk;
1258 struct hci_dev *hdev;
1259 u8 mgmt_status;
1260};
1261
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001262static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001263{
1264 struct cmd_lookup *match = data;
1265
1266 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1267
1268 list_del(&cmd->list);
1269
1270 if (match->sk == NULL) {
1271 match->sk = cmd->sk;
1272 sock_hold(match->sk);
1273 }
1274
1275 mgmt_pending_free(cmd);
1276}
1277
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001278static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001279{
1280 u8 *status = data;
1281
Johan Hedberga69e8372015-03-06 21:08:53 +02001282 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001283 mgmt_pending_remove(cmd);
1284}
1285
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001286static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001287{
1288 if (cmd->cmd_complete) {
1289 u8 *status = data;
1290
1291 cmd->cmd_complete(cmd, *status);
1292 mgmt_pending_remove(cmd);
1293
1294 return;
1295 }
1296
1297 cmd_status_rsp(cmd, data);
1298}
1299
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001300static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001301{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001302 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1303 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001304}
1305
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001306static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001307{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001308 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1309 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001310}
1311
Johan Hedberge6fe7982013-10-02 15:45:22 +03001312static u8 mgmt_bredr_support(struct hci_dev *hdev)
1313{
1314 if (!lmp_bredr_capable(hdev))
1315 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001316 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001317 return MGMT_STATUS_REJECTED;
1318 else
1319 return MGMT_STATUS_SUCCESS;
1320}
1321
1322static u8 mgmt_le_support(struct hci_dev *hdev)
1323{
1324 if (!lmp_le_capable(hdev))
1325 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001326 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001327 return MGMT_STATUS_REJECTED;
1328 else
1329 return MGMT_STATUS_SUCCESS;
1330}
1331
Johan Hedbergaed1a882015-11-22 17:24:44 +03001332void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001333{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001334 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001335
Marcel Holtmann181d6952020-05-06 09:57:47 +02001336 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001337
1338 hci_dev_lock(hdev);
1339
Johan Hedberg333ae952015-03-17 13:48:47 +02001340 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001341 if (!cmd)
1342 goto unlock;
1343
1344 if (status) {
1345 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001346 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001347 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348 goto remove_cmd;
1349 }
1350
Johan Hedbergaed1a882015-11-22 17:24:44 +03001351 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1352 hdev->discov_timeout > 0) {
1353 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1354 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001355 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001356
1357 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001358 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001359
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001360remove_cmd:
1361 mgmt_pending_remove(cmd);
1362
1363unlock:
1364 hci_dev_unlock(hdev);
1365}
1366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001367static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001368 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001369{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001370 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001371 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001372 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001373 int err;
1374
Marcel Holtmann181d6952020-05-06 09:57:47 +02001375 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001376
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001377 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1378 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001379 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1380 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001381
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001382 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001383 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1384 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001385
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001386 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001387
1388 /* Disabling discoverable requires that no timeout is set,
1389 * and enabling limited discoverable requires a timeout.
1390 */
1391 if ((cp->val == 0x00 && timeout > 0) ||
1392 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001393 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1394 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001395
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001396 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001397
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001398 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001399 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1400 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001401 goto failed;
1402 }
1403
Johan Hedberg333ae952015-03-17 13:48:47 +02001404 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1405 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001406 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1407 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408 goto failed;
1409 }
1410
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001411 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001412 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1413 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001414 goto failed;
1415 }
1416
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001417 if (hdev->advertising_paused) {
1418 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1419 MGMT_STATUS_BUSY);
1420 goto failed;
1421 }
1422
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001423 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001424 bool changed = false;
1425
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001426 /* Setting limited discoverable when powered off is
1427 * not a valid operation since it requires a timeout
1428 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1429 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001430 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001431 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001432 changed = true;
1433 }
1434
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001435 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001436 if (err < 0)
1437 goto failed;
1438
1439 if (changed)
1440 err = new_settings(hdev, sk);
1441
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001442 goto failed;
1443 }
1444
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001445 /* If the current mode is the same, then just update the timeout
1446 * value with the new value. And if only the timeout gets updated,
1447 * then no need for any HCI transactions.
1448 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001449 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1450 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1451 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001452 cancel_delayed_work(&hdev->discov_off);
1453 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001454
Marcel Holtmann36261542013-10-15 08:28:51 -07001455 if (cp->val && hdev->discov_timeout > 0) {
1456 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001457 queue_delayed_work(hdev->req_workqueue,
1458 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001459 }
1460
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001461 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001462 goto failed;
1463 }
1464
1465 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1466 if (!cmd) {
1467 err = -ENOMEM;
1468 goto failed;
1469 }
1470
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001471 /* Cancel any potential discoverable timeout that might be
1472 * still active and store new timeout value. The arming of
1473 * the timeout happens in the complete handler.
1474 */
1475 cancel_delayed_work(&hdev->discov_off);
1476 hdev->discov_timeout = timeout;
1477
Johan Hedbergaed1a882015-11-22 17:24:44 +03001478 if (cp->val)
1479 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1480 else
1481 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1482
Johan Hedbergb456f872013-10-19 23:38:22 +03001483 /* Limited discoverable mode */
1484 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001485 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001486 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001487 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001488
Johan Hedbergaed1a882015-11-22 17:24:44 +03001489 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1490 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001491
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001492failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001493 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001494 return err;
1495}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001496
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001497void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001498{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001499 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001500
Marcel Holtmann181d6952020-05-06 09:57:47 +02001501 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001502
1503 hci_dev_lock(hdev);
1504
Johan Hedberg333ae952015-03-17 13:48:47 +02001505 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001506 if (!cmd)
1507 goto unlock;
1508
Johan Hedberg37438c12013-10-14 16:20:05 +03001509 if (status) {
1510 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001511 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001512 goto remove_cmd;
1513 }
1514
Johan Hedberg2b76f452013-03-15 17:07:04 -05001515 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001516 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001517
Johan Hedberg37438c12013-10-14 16:20:05 +03001518remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001519 mgmt_pending_remove(cmd);
1520
1521unlock:
1522 hci_dev_unlock(hdev);
1523}
1524
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001525static int set_connectable_update_settings(struct hci_dev *hdev,
1526 struct sock *sk, u8 val)
1527{
1528 bool changed = false;
1529 int err;
1530
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001531 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001532 changed = true;
1533
1534 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001535 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001536 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001537 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1538 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001539 }
1540
1541 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1542 if (err < 0)
1543 return err;
1544
Johan Hedberg562064e2014-07-08 16:35:34 +03001545 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001546 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001547 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001548 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001549 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001550
1551 return 0;
1552}
1553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001554static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001555 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001557 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001558 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001559 int err;
1560
Marcel Holtmann181d6952020-05-06 09:57:47 +02001561 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001562
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001563 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1564 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1566 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001567
Johan Hedberga7e80f22013-01-09 16:05:19 +02001568 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1570 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001571
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001572 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001573
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001574 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001575 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001576 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001577 }
1578
Johan Hedberg333ae952015-03-17 13:48:47 +02001579 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1580 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001581 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1582 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001583 goto failed;
1584 }
1585
Johan Hedberg73f22f62010-12-29 16:00:25 +02001586 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1587 if (!cmd) {
1588 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001589 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001590 }
1591
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001592 if (cp->val) {
1593 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1594 } else {
1595 if (hdev->discov_timeout > 0)
1596 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001597
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001598 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1599 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1600 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001601 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001602
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001603 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1604 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001605
1606failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001607 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001608 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001609}
1610
Johan Hedbergb2939472014-07-30 09:22:23 +03001611static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001612 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001613{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001614 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001615 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001616 int err;
1617
Marcel Holtmann181d6952020-05-06 09:57:47 +02001618 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001619
Johan Hedberga7e80f22013-01-09 16:05:19 +02001620 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001621 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001625
1626 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001627 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001628 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001629 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001630
Johan Hedbergb2939472014-07-30 09:22:23 +03001631 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001632 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001633 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001634
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001635 if (changed) {
1636 /* In limited privacy mode the change of bondable mode
1637 * may affect the local advertising address.
1638 */
1639 if (hdev_is_powered(hdev) &&
1640 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1641 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1642 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1643 queue_work(hdev->req_workqueue,
1644 &hdev->discoverable_update);
1645
Marcel Holtmann55594352013-10-06 16:11:57 -07001646 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001647 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001648
Marcel Holtmann55594352013-10-06 16:11:57 -07001649unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001650 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001651 return err;
1652}
1653
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001654static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1655 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001656{
1657 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001658 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001659 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001660 int err;
1661
Marcel Holtmann181d6952020-05-06 09:57:47 +02001662 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001663
Johan Hedberge6fe7982013-10-02 15:45:22 +03001664 status = mgmt_bredr_support(hdev);
1665 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001666 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1667 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001668
Johan Hedberga7e80f22013-01-09 16:05:19 +02001669 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1671 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001672
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001673 hci_dev_lock(hdev);
1674
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001675 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001676 bool changed = false;
1677
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001678 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001679 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001680 changed = true;
1681 }
1682
1683 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1684 if (err < 0)
1685 goto failed;
1686
1687 if (changed)
1688 err = new_settings(hdev, sk);
1689
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001690 goto failed;
1691 }
1692
Johan Hedberg333ae952015-03-17 13:48:47 +02001693 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001694 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1695 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001696 goto failed;
1697 }
1698
1699 val = !!cp->val;
1700
1701 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1702 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1703 goto failed;
1704 }
1705
1706 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1707 if (!cmd) {
1708 err = -ENOMEM;
1709 goto failed;
1710 }
1711
1712 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1713 if (err < 0) {
1714 mgmt_pending_remove(cmd);
1715 goto failed;
1716 }
1717
1718failed:
1719 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001720 return err;
1721}
1722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001723static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001724{
1725 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001726 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001727 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001728 int err;
1729
Marcel Holtmann181d6952020-05-06 09:57:47 +02001730 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001731
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001732 status = mgmt_bredr_support(hdev);
1733 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001735
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001736 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001737 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1738 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001739
Johan Hedberga7e80f22013-01-09 16:05:19 +02001740 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001741 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1742 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001743
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001744 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001745
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001746 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001747 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001748
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001749 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001750 changed = !hci_dev_test_and_set_flag(hdev,
1751 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001752 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001753 changed = hci_dev_test_and_clear_flag(hdev,
1754 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001755 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001756 changed = hci_dev_test_and_clear_flag(hdev,
1757 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001758 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001759 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001760 }
1761
1762 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1763 if (err < 0)
1764 goto failed;
1765
1766 if (changed)
1767 err = new_settings(hdev, sk);
1768
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001769 goto failed;
1770 }
1771
Johan Hedberg333ae952015-03-17 13:48:47 +02001772 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001773 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1774 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001775 goto failed;
1776 }
1777
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001778 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001779 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1780 goto failed;
1781 }
1782
1783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1784 if (!cmd) {
1785 err = -ENOMEM;
1786 goto failed;
1787 }
1788
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001789 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001790 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1791 sizeof(cp->val), &cp->val);
1792
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001793 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001794 if (err < 0) {
1795 mgmt_pending_remove(cmd);
1796 goto failed;
1797 }
1798
1799failed:
1800 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001801 return err;
1802}
1803
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001804static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001805{
1806 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001807 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001808 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001809 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001810
Marcel Holtmann181d6952020-05-06 09:57:47 +02001811 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001812
Johan Hedberge6fe7982013-10-02 15:45:22 +03001813 status = mgmt_bredr_support(hdev);
1814 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001816
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001817 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001818 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1819 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001820
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001821 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1823 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001824
Johan Hedberga7e80f22013-01-09 16:05:19 +02001825 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001826 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1827 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001828
Marcel Holtmannee392692013-10-01 22:59:23 -07001829 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001830
Johan Hedberg333ae952015-03-17 13:48:47 +02001831 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001832 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1833 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001834 goto unlock;
1835 }
1836
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001837 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001838 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001839 } else {
1840 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001841 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1842 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001843 goto unlock;
1844 }
1845
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001846 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001847 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001848
1849 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1850 if (err < 0)
1851 goto unlock;
1852
1853 if (changed)
1854 err = new_settings(hdev, sk);
1855
1856unlock:
1857 hci_dev_unlock(hdev);
1858 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001859}
1860
Marcel Holtmann1904a852015-01-11 13:50:44 -08001861static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001862{
1863 struct cmd_lookup match = { NULL, hdev };
1864
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301865 hci_dev_lock(hdev);
1866
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867 if (status) {
1868 u8 mgmt_err = mgmt_status(status);
1869
1870 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1871 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301872 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001873 }
1874
1875 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1876
1877 new_settings(hdev, match.sk);
1878
1879 if (match.sk)
1880 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001881
1882 /* Make sure the controller has a good default for
1883 * advertising data. Restrict the update to when LE
1884 * has actually been enabled. During power on, the
1885 * update in powered_update_hci will take care of it.
1886 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001887 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001888 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001889 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301890 if (ext_adv_capable(hdev)) {
1891 int err;
1892
1893 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1894 if (!err)
1895 __hci_req_update_scan_rsp_data(&req, 0x00);
1896 } else {
1897 __hci_req_update_adv_data(&req, 0x00);
1898 __hci_req_update_scan_rsp_data(&req, 0x00);
1899 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001900 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001901 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001902 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301903
1904unlock:
1905 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001906}
1907
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001908static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909{
1910 struct mgmt_mode *cp = data;
1911 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001912 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001913 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001915 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001916
Marcel Holtmann181d6952020-05-06 09:57:47 +02001917 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001918
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001919 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001920 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1921 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001922
Johan Hedberga7e80f22013-01-09 16:05:19 +02001923 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001924 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1925 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001926
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001927 /* Bluetooth single mode LE only controllers or dual-mode
1928 * controllers configured as LE only devices, do not allow
1929 * switching LE off. These have either LE enabled explicitly
1930 * or BR/EDR has been previously switched off.
1931 *
1932 * When trying to enable an already enabled LE, then gracefully
1933 * send a positive response. Trying to disable it however will
1934 * result into rejection.
1935 */
1936 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1937 if (cp->val == 0x01)
1938 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1939
Johan Hedberga69e8372015-03-06 21:08:53 +02001940 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1941 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001942 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001943
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001944 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001945
1946 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001947 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001948
Florian Grandel847818d2015-06-18 03:16:46 +02001949 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001950 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001951
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001952 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001953 bool changed = false;
1954
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001955 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001956 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001957 changed = true;
1958 }
1959
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001960 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001961 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001962 changed = true;
1963 }
1964
Johan Hedberg06199cf2012-02-22 16:37:11 +02001965 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1966 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001967 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001968
1969 if (changed)
1970 err = new_settings(hdev, sk);
1971
Johan Hedberg1de028c2012-02-29 19:55:35 -08001972 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973 }
1974
Johan Hedberg333ae952015-03-17 13:48:47 +02001975 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1976 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001977 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1978 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001979 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001980 }
1981
1982 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1983 if (!cmd) {
1984 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001985 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001986 }
1987
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001988 hci_req_init(&req, hdev);
1989
Johan Hedberg06199cf2012-02-22 16:37:11 +02001990 memset(&hci_cp, 0, sizeof(hci_cp));
1991
1992 if (val) {
1993 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001994 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001995 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001996 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001997 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301998
1999 if (ext_adv_capable(hdev))
2000 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002001 }
2002
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002003 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2004 &hci_cp);
2005
2006 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302007 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002008 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002009
Johan Hedberg1de028c2012-02-29 19:55:35 -08002010unlock:
2011 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002012 return err;
2013}
2014
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002015/* This is a helper function to test for pending mgmt commands that can
2016 * cause CoD or EIR HCI commands. We can only allow one such pending
2017 * mgmt command at a time since otherwise we cannot easily track what
2018 * the current values are, will be, and based on that calculate if a new
2019 * HCI command needs to be sent and if yes with what value.
2020 */
2021static bool pending_eir_or_class(struct hci_dev *hdev)
2022{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002023 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002024
2025 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2026 switch (cmd->opcode) {
2027 case MGMT_OP_ADD_UUID:
2028 case MGMT_OP_REMOVE_UUID:
2029 case MGMT_OP_SET_DEV_CLASS:
2030 case MGMT_OP_SET_POWERED:
2031 return true;
2032 }
2033 }
2034
2035 return false;
2036}
2037
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002038static const u8 bluetooth_base_uuid[] = {
2039 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2040 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2041};
2042
2043static u8 get_uuid_size(const u8 *uuid)
2044{
2045 u32 val;
2046
2047 if (memcmp(uuid, bluetooth_base_uuid, 12))
2048 return 128;
2049
2050 val = get_unaligned_le32(&uuid[12]);
2051 if (val > 0xffff)
2052 return 32;
2053
2054 return 16;
2055}
2056
Johan Hedberg92da6092013-03-15 17:06:55 -05002057static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2058{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002059 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002060
2061 hci_dev_lock(hdev);
2062
Johan Hedberg333ae952015-03-17 13:48:47 +02002063 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002064 if (!cmd)
2065 goto unlock;
2066
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002067 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2068 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002069
2070 mgmt_pending_remove(cmd);
2071
2072unlock:
2073 hci_dev_unlock(hdev);
2074}
2075
Marcel Holtmann1904a852015-01-11 13:50:44 -08002076static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002077{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002078 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002079
2080 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2081}
2082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002085 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002086 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002087 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 int err;
2090
Marcel Holtmann181d6952020-05-06 09:57:47 +02002091 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002093 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002095 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002096 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2097 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002098 goto failed;
2099 }
2100
Andre Guedes92c4c202012-06-07 19:05:44 -03002101 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002102 if (!uuid) {
2103 err = -ENOMEM;
2104 goto failed;
2105 }
2106
2107 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002108 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002109 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002110
Johan Hedbergde66aa62013-01-27 00:31:27 +02002111 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002112
Johan Hedberg890ea892013-03-15 17:06:52 -05002113 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002114
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002115 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002116 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002117
Johan Hedberg92da6092013-03-15 17:06:55 -05002118 err = hci_req_run(&req, add_uuid_complete);
2119 if (err < 0) {
2120 if (err != -ENODATA)
2121 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002122
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002123 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2124 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002125 goto failed;
2126 }
2127
2128 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002129 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002130 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002131 goto failed;
2132 }
2133
2134 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002135
2136failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002137 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002138 return err;
2139}
2140
Johan Hedberg24b78d02012-02-23 23:24:30 +02002141static bool enable_service_cache(struct hci_dev *hdev)
2142{
2143 if (!hdev_is_powered(hdev))
2144 return false;
2145
Marcel Holtmann238be782015-03-13 02:11:06 -07002146 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002147 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2148 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002149 return true;
2150 }
2151
2152 return false;
2153}
2154
Marcel Holtmann1904a852015-01-11 13:50:44 -08002155static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002156{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002157 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002158
2159 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2160}
2161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002162static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002163 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002165 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002166 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002167 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002168 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 -05002169 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170 int err, found;
2171
Marcel Holtmann181d6952020-05-06 09:57:47 +02002172 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002175
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002176 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002177 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2178 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002179 goto unlock;
2180 }
2181
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002182 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002183 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002184
Johan Hedberg24b78d02012-02-23 23:24:30 +02002185 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002186 err = mgmt_cmd_complete(sk, hdev->id,
2187 MGMT_OP_REMOVE_UUID,
2188 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002189 goto unlock;
2190 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002191
Johan Hedberg9246a862012-02-23 21:33:16 +02002192 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002193 }
2194
2195 found = 0;
2196
Johan Hedberg056341c2013-01-27 00:31:30 +02002197 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002198 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2199 continue;
2200
2201 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002202 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002203 found++;
2204 }
2205
2206 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002207 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2208 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002209 goto unlock;
2210 }
2211
Johan Hedberg9246a862012-02-23 21:33:16 +02002212update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002213 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002214
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002215 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002216 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002217
Johan Hedberg92da6092013-03-15 17:06:55 -05002218 err = hci_req_run(&req, remove_uuid_complete);
2219 if (err < 0) {
2220 if (err != -ENODATA)
2221 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002222
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002223 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2224 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002225 goto unlock;
2226 }
2227
2228 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002229 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002230 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002231 goto unlock;
2232 }
2233
2234 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002235
2236unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002237 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002238 return err;
2239}
2240
Marcel Holtmann1904a852015-01-11 13:50:44 -08002241static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002242{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002243 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002244
2245 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2246}
2247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002248static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002249 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002250{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002251 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002252 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002253 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002254 int err;
2255
Marcel Holtmann181d6952020-05-06 09:57:47 +02002256 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002257
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002258 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002259 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2260 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002263
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002264 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002265 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2266 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002267 goto unlock;
2268 }
2269
2270 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002271 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2272 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002273 goto unlock;
2274 }
2275
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002276 hdev->major_class = cp->major;
2277 hdev->minor_class = cp->minor;
2278
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002279 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002280 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2281 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002282 goto unlock;
2283 }
2284
Johan Hedberg890ea892013-03-15 17:06:52 -05002285 hci_req_init(&req, hdev);
2286
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002287 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002288 hci_dev_unlock(hdev);
2289 cancel_delayed_work_sync(&hdev->service_cache);
2290 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002291 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002292 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002293
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002294 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002295
Johan Hedberg92da6092013-03-15 17:06:55 -05002296 err = hci_req_run(&req, set_class_complete);
2297 if (err < 0) {
2298 if (err != -ENODATA)
2299 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002300
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002301 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2302 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002303 goto unlock;
2304 }
2305
2306 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002307 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002308 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002309 goto unlock;
2310 }
2311
2312 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002313
Johan Hedbergb5235a62012-02-21 14:32:24 +02002314unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002315 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002316 return err;
2317}
2318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002319static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002320 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002321{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002322 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002323 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2324 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002325 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002326 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002327 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002328
Marcel Holtmann181d6952020-05-06 09:57:47 +02002329 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002330
2331 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002332 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2333 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002334
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002335 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002336 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002337 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2338 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002339 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002341 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002342
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002343 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002344 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002345 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2346 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002347 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2348 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002349 }
2350
Johan Hedberg4ae143012013-01-20 14:27:13 +02002351 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002352 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002354
Marcel Holtmann181d6952020-05-06 09:57:47 +02002355 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2356 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002357
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002358 for (i = 0; i < key_count; i++) {
2359 struct mgmt_link_key_info *key = &cp->keys[i];
2360
Marcel Holtmann8e991132014-01-10 02:07:25 -08002361 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002362 return mgmt_cmd_status(sk, hdev->id,
2363 MGMT_OP_LOAD_LINK_KEYS,
2364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002365 }
2366
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002367 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002368
2369 hci_link_keys_clear(hdev);
2370
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002371 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002372 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002374 changed = hci_dev_test_and_clear_flag(hdev,
2375 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002376
2377 if (changed)
2378 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002379
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002380 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002381 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002382
Alain Michaud600a8742020-01-07 00:43:17 +00002383 if (hci_is_blocked_key(hdev,
2384 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2385 key->val)) {
2386 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2387 &key->addr.bdaddr);
2388 continue;
2389 }
2390
Johan Hedberg58e92932014-06-24 14:00:26 +03002391 /* Always ignore debug keys and require a new pairing if
2392 * the user wants to use them.
2393 */
2394 if (key->type == HCI_LK_DEBUG_COMBINATION)
2395 continue;
2396
Johan Hedberg7652ff62014-06-24 13:15:49 +03002397 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2398 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002399 }
2400
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002401 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002402
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002403 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002404
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002405 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002406}
2407
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002408static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002410{
2411 struct mgmt_ev_device_unpaired ev;
2412
2413 bacpy(&ev.addr.bdaddr, bdaddr);
2414 ev.addr.type = addr_type;
2415
2416 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002417 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002418}
2419
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002420static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002421 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002422{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002423 struct mgmt_cp_unpair_device *cp = data;
2424 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002425 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002426 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002427 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002428 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002429 int err;
2430
Johan Hedberga8a1d192011-11-10 15:54:38 +02002431 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002432 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2433 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002434
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002435 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002436 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2437 MGMT_STATUS_INVALID_PARAMS,
2438 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002439
Johan Hedberg118da702013-01-20 14:27:20 +02002440 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002441 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_INVALID_PARAMS,
2443 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002444
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002445 hci_dev_lock(hdev);
2446
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002447 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002448 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2449 MGMT_STATUS_NOT_POWERED, &rp,
2450 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002451 goto unlock;
2452 }
2453
Johan Hedberge0b2b272014-02-18 17:14:31 +02002454 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002455 /* If disconnection is requested, then look up the
2456 * connection. If the remote device is connected, it
2457 * will be later used to terminate the link.
2458 *
2459 * Setting it to NULL explicitly will cause no
2460 * termination of the link.
2461 */
2462 if (cp->disconnect)
2463 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2464 &cp->addr.bdaddr);
2465 else
2466 conn = NULL;
2467
Johan Hedberg124f6e32012-02-09 13:50:12 +02002468 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002469 if (err < 0) {
2470 err = mgmt_cmd_complete(sk, hdev->id,
2471 MGMT_OP_UNPAIR_DEVICE,
2472 MGMT_STATUS_NOT_PAIRED, &rp,
2473 sizeof(rp));
2474 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002475 }
2476
Johan Hedbergec182f02015-10-21 18:03:03 +03002477 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002478 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002479
Johan Hedbergec182f02015-10-21 18:03:03 +03002480 /* LE address type */
2481 addr_type = le_addr_type(cp->addr.type);
2482
Matias Karhumaacb28c302018-09-26 09:13:46 +03002483 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2484 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002486 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2487 MGMT_STATUS_NOT_PAIRED, &rp,
2488 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002489 goto unlock;
2490 }
2491
Johan Hedbergec182f02015-10-21 18:03:03 +03002492 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2493 if (!conn) {
2494 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2495 goto done;
2496 }
2497
Johan Hedbergc81d5552015-10-22 09:38:35 +03002498
Johan Hedbergec182f02015-10-21 18:03:03 +03002499 /* Defer clearing up the connection parameters until closing to
2500 * give a chance of keeping them if a repairing happens.
2501 */
2502 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2503
Johan Hedbergfc643612015-10-22 09:38:31 +03002504 /* Disable auto-connection parameters if present */
2505 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2506 if (params) {
2507 if (params->explicit_connect)
2508 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2509 else
2510 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2511 }
2512
Johan Hedbergec182f02015-10-21 18:03:03 +03002513 /* If disconnection is not requested, then clear the connection
2514 * variable so that the link is not terminated.
2515 */
2516 if (!cp->disconnect)
2517 conn = NULL;
2518
2519done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002520 /* If the connection variable is set, then termination of the
2521 * link is requested.
2522 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002523 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002524 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2525 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002526 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002527 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002528 }
2529
Johan Hedberg124f6e32012-02-09 13:50:12 +02002530 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002532 if (!cmd) {
2533 err = -ENOMEM;
2534 goto unlock;
2535 }
2536
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002537 cmd->cmd_complete = addr_cmd_complete;
2538
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002539 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002540 if (err < 0)
2541 mgmt_pending_remove(cmd);
2542
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002543unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002544 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002545 return err;
2546}
2547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002551 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002552 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002553 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002554 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555 int err;
2556
Marcel Holtmann181d6952020-05-06 09:57:47 +02002557 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002558
Johan Hedberg06a63b12013-01-20 14:27:21 +02002559 memset(&rp, 0, sizeof(rp));
2560 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2561 rp.addr.type = cp->addr.type;
2562
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002563 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002564 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2565 MGMT_STATUS_INVALID_PARAMS,
2566 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002568 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002569
2570 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002571 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2572 MGMT_STATUS_NOT_POWERED, &rp,
2573 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002574 goto failed;
2575 }
2576
Johan Hedberg333ae952015-03-17 13:48:47 +02002577 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002578 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2579 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002580 goto failed;
2581 }
2582
Andre Guedes591f47f2012-04-24 21:02:49 -03002583 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002584 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2585 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002586 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002587 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2588 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002589
Vishal Agarwalf9607272012-06-13 05:32:43 +05302590 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002591 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2592 MGMT_STATUS_NOT_CONNECTED, &rp,
2593 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002594 goto failed;
2595 }
2596
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002597 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002598 if (!cmd) {
2599 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002600 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002601 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002602
Johan Hedbergf5818c22014-12-05 13:36:02 +02002603 cmd->cmd_complete = generic_cmd_complete;
2604
Johan Hedberge3f2f922014-08-18 20:33:33 +03002605 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002606 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002607 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002608
2609failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002610 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002611 return err;
2612}
2613
Andre Guedes57c14772012-04-24 21:02:50 -03002614static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002615{
2616 switch (link_type) {
2617 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002618 switch (addr_type) {
2619 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002620 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002621
Johan Hedberg48264f02011-11-09 13:58:58 +02002622 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002623 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002624 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002625 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002626
Johan Hedberg4c659c32011-11-07 23:13:39 +02002627 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002628 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002629 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002630 }
2631}
2632
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002633static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2634 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002635{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002636 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002637 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002638 int err;
2639 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640
Marcel Holtmann181d6952020-05-06 09:57:47 +02002641 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002642
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002643 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002644
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002645 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002646 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2647 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002648 goto unlock;
2649 }
2650
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002651 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002652 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2653 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002654 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002655 }
2656
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002657 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002658 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002659 err = -ENOMEM;
2660 goto unlock;
2661 }
2662
Johan Hedberg2784eb42011-01-21 13:56:35 +02002663 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002664 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002665 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2666 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002667 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002668 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002669 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002670 continue;
2671 i++;
2672 }
2673
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002674 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002675
Johan Hedberg4c659c32011-11-07 23:13:39 +02002676 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002677 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002678 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002679
Johan Hedberga38528f2011-01-22 06:46:43 +02002680 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002681
2682unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002684 return err;
2685}
2686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002688 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002689{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002690 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002691 int err;
2692
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002693 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002694 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002695 if (!cmd)
2696 return -ENOMEM;
2697
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002698 cmd->cmd_complete = addr_cmd_complete;
2699
Johan Hedbergd8457692012-02-17 14:24:57 +02002700 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002701 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002702 if (err < 0)
2703 mgmt_pending_remove(cmd);
2704
2705 return err;
2706}
2707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002708static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002709 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002710{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002711 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002714 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715 int err;
2716
Marcel Holtmann181d6952020-05-06 09:57:47 +02002717 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002719 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002721 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002722 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2723 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002724 goto failed;
2725 }
2726
Johan Hedbergd8457692012-02-17 14:24:57 +02002727 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002728 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002729 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2730 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002731 goto failed;
2732 }
2733
2734 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002735 struct mgmt_cp_pin_code_neg_reply ncp;
2736
2737 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002738
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002739 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002740
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002741 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002742 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002743 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2744 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002745
2746 goto failed;
2747 }
2748
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002749 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002750 if (!cmd) {
2751 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002752 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002753 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002754
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002755 cmd->cmd_complete = addr_cmd_complete;
2756
Johan Hedbergd8457692012-02-17 14:24:57 +02002757 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002758 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002759 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002760
2761 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2762 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002763 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002764
2765failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002766 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002767 return err;
2768}
2769
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002770static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2771 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002773 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002774
Marcel Holtmann181d6952020-05-06 09:57:47 +02002775 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002776
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002777 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002778 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2779 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002782
2783 hdev->io_capability = cp->io_capability;
2784
Marcel Holtmann181d6952020-05-06 09:57:47 +02002785 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002786
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002787 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002788
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002789 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2790 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002791}
2792
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002793static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002794{
2795 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002796 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002797
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002798 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2800 continue;
2801
Johan Hedberge9a416b2011-02-19 12:05:56 -03002802 if (cmd->user_data != conn)
2803 continue;
2804
2805 return cmd;
2806 }
2807
2808 return NULL;
2809}
2810
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002811static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002812{
2813 struct mgmt_rp_pair_device rp;
2814 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002815 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002816
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002817 bacpy(&rp.addr.bdaddr, &conn->dst);
2818 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002820 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2821 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002822
2823 /* So we don't get further callbacks for this connection */
2824 conn->connect_cfm_cb = NULL;
2825 conn->security_cfm_cb = NULL;
2826 conn->disconn_cfm_cb = NULL;
2827
David Herrmann76a68ba2013-04-06 20:28:37 +02002828 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002829
2830 /* The device is paired so there is no need to remove
2831 * its connection parameters anymore.
2832 */
2833 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002834
2835 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002836
2837 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002838}
2839
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002840void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2841{
2842 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002843 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002844
2845 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002846 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002847 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002848 mgmt_pending_remove(cmd);
2849 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002850}
2851
Johan Hedberge9a416b2011-02-19 12:05:56 -03002852static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2853{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002854 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855
2856 BT_DBG("status %u", status);
2857
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002858 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002859 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002860 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002861 return;
2862 }
2863
2864 cmd->cmd_complete(cmd, mgmt_status(status));
2865 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002866}
2867
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002868static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002870 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302871
2872 BT_DBG("status %u", status);
2873
2874 if (!status)
2875 return;
2876
2877 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002878 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302879 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002880 return;
2881 }
2882
2883 cmd->cmd_complete(cmd, mgmt_status(status));
2884 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302885}
2886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002887static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002888 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002889{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002890 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002891 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002892 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002893 u8 sec_level, auth_type;
2894 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002895 int err;
2896
Marcel Holtmann181d6952020-05-06 09:57:47 +02002897 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002898
Szymon Jancf950a30e2013-01-18 12:48:07 +01002899 memset(&rp, 0, sizeof(rp));
2900 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2901 rp.addr.type = cp->addr.type;
2902
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002903 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002904 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2905 MGMT_STATUS_INVALID_PARAMS,
2906 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002907
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002908 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002909 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2910 MGMT_STATUS_INVALID_PARAMS,
2911 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002913 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002914
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002915 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002916 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2917 MGMT_STATUS_NOT_POWERED, &rp,
2918 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002919 goto unlock;
2920 }
2921
Johan Hedberg55e76b32015-03-10 22:34:40 +02002922 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2923 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2924 MGMT_STATUS_ALREADY_PAIRED, &rp,
2925 sizeof(rp));
2926 goto unlock;
2927 }
2928
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002929 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002930 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002931
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002932 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002933 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
Manish Mandlik76b13992020-06-17 16:39:19 +02002934 auth_type, CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002935 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002936 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002937 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002938
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002939 /* When pairing a new device, it is expected to remember
2940 * this device for future connections. Adding the connection
2941 * parameter information ahead of time allows tracking
2942 * of the slave preferred values and will speed up any
2943 * further connection establishment.
2944 *
2945 * If connection parameters already exist, then they
2946 * will be kept and this function does nothing.
2947 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002948 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2949
2950 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2951 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002952
Manish Mandlik76b13992020-06-17 16:39:19 +02002953 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, addr_type,
2954 sec_level, HCI_LE_CONN_TIMEOUT,
2955 CONN_REASON_PAIR_DEVICE);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002956 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002957
Ville Tervo30e76272011-02-22 16:10:53 -03002958 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002959 int status;
2960
2961 if (PTR_ERR(conn) == -EBUSY)
2962 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002963 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2964 status = MGMT_STATUS_NOT_SUPPORTED;
2965 else if (PTR_ERR(conn) == -ECONNREFUSED)
2966 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002967 else
2968 status = MGMT_STATUS_CONNECT_FAILED;
2969
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2971 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002972 goto unlock;
2973 }
2974
2975 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002976 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002977 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2978 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002979 goto unlock;
2980 }
2981
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002982 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002983 if (!cmd) {
2984 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002985 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002986 goto unlock;
2987 }
2988
Johan Hedberg04ab2742014-12-05 13:36:04 +02002989 cmd->cmd_complete = pairing_complete;
2990
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002991 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002992 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002993 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002994 conn->security_cfm_cb = pairing_complete_cb;
2995 conn->disconn_cfm_cb = pairing_complete_cb;
2996 } else {
2997 conn->connect_cfm_cb = le_pairing_complete_cb;
2998 conn->security_cfm_cb = le_pairing_complete_cb;
2999 conn->disconn_cfm_cb = le_pairing_complete_cb;
3000 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003001
Johan Hedberge9a416b2011-02-19 12:05:56 -03003002 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003003 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003004
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003005 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003006 hci_conn_security(conn, sec_level, auth_type, true)) {
3007 cmd->cmd_complete(cmd, 0);
3008 mgmt_pending_remove(cmd);
3009 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003010
3011 err = 0;
3012
3013unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003014 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003015 return err;
3016}
3017
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3019 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003020{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003021 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003022 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003023 struct hci_conn *conn;
3024 int err;
3025
Marcel Holtmann181d6952020-05-06 09:57:47 +02003026 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003027
Johan Hedberg28424702012-02-02 04:02:29 +02003028 hci_dev_lock(hdev);
3029
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003030 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003031 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3032 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003033 goto unlock;
3034 }
3035
Johan Hedberg333ae952015-03-17 13:48:47 +02003036 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003037 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003038 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3039 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003040 goto unlock;
3041 }
3042
3043 conn = cmd->user_data;
3044
3045 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003046 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3047 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003048 goto unlock;
3049 }
3050
Johan Hedberga511b352014-12-11 21:45:45 +02003051 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3052 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003053
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003054 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3055 addr, sizeof(*addr));
Manish Mandlik76b13992020-06-17 16:39:19 +02003056
3057 /* Since user doesn't want to proceed with the connection, abort any
3058 * ongoing pairing and then terminate the link if it was created
3059 * because of the pair device action.
3060 */
3061 if (addr->type == BDADDR_BREDR)
3062 hci_remove_link_key(hdev, &addr->bdaddr);
3063 else
3064 smp_cancel_and_remove_pairing(hdev, &addr->bdaddr,
3065 le_addr_type(addr->type));
3066
3067 if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
3068 hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
3069
Johan Hedberg28424702012-02-02 04:02:29 +02003070unlock:
3071 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003072 return err;
3073}
3074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003075static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003076 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003077 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003078{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003079 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003080 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003081 int err;
3082
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003083 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003084
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003085 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003086 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3087 MGMT_STATUS_NOT_POWERED, addr,
3088 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003089 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003090 }
3091
Johan Hedberg1707c602013-03-15 17:07:15 -05003092 if (addr->type == BDADDR_BREDR)
3093 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003094 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003095 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3096 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003097
Johan Hedberg272d90d2012-02-09 15:26:12 +02003098 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003099 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3100 MGMT_STATUS_NOT_CONNECTED, addr,
3101 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003102 goto done;
3103 }
3104
Johan Hedberg1707c602013-03-15 17:07:15 -05003105 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003106 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003107 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003108 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3109 MGMT_STATUS_SUCCESS, addr,
3110 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003111 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003112 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3113 MGMT_STATUS_FAILED, addr,
3114 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003115
Brian Gix47c15e22011-11-16 13:53:14 -08003116 goto done;
3117 }
3118
Johan Hedberg1707c602013-03-15 17:07:15 -05003119 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003120 if (!cmd) {
3121 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003122 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003123 }
3124
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003125 cmd->cmd_complete = addr_cmd_complete;
3126
Brian Gix0df4c182011-11-16 13:53:13 -08003127 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003128 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3129 struct hci_cp_user_passkey_reply cp;
3130
Johan Hedberg1707c602013-03-15 17:07:15 -05003131 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003132 cp.passkey = passkey;
3133 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3134 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003135 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3136 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003137
Johan Hedberga664b5b2011-02-19 12:06:02 -03003138 if (err < 0)
3139 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003140
Brian Gix0df4c182011-11-16 13:53:13 -08003141done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003142 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003143 return err;
3144}
3145
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303146static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3147 void *data, u16 len)
3148{
3149 struct mgmt_cp_pin_code_neg_reply *cp = data;
3150
Marcel Holtmann181d6952020-05-06 09:57:47 +02003151 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303152
Johan Hedberg1707c602013-03-15 17:07:15 -05003153 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303154 MGMT_OP_PIN_CODE_NEG_REPLY,
3155 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3156}
3157
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3159 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003160{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003161 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003162
Marcel Holtmann181d6952020-05-06 09:57:47 +02003163 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003164
3165 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003166 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3167 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003168
Johan Hedberg1707c602013-03-15 17:07:15 -05003169 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 MGMT_OP_USER_CONFIRM_REPLY,
3171 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003172}
3173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003174static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003176{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003177 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003178
Marcel Holtmann181d6952020-05-06 09:57:47 +02003179 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003180
Johan Hedberg1707c602013-03-15 17:07:15 -05003181 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003182 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3183 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003184}
3185
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003186static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3187 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003188{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003189 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003190
Marcel Holtmann181d6952020-05-06 09:57:47 +02003191 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003192
Johan Hedberg1707c602013-03-15 17:07:15 -05003193 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 MGMT_OP_USER_PASSKEY_REPLY,
3195 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003196}
3197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003198static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003199 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003201 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003202
Marcel Holtmann181d6952020-05-06 09:57:47 +02003203 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003204
Johan Hedberg1707c602013-03-15 17:07:15 -05003205 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3207 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003208}
3209
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003210static void adv_expire(struct hci_dev *hdev, u32 flags)
3211{
3212 struct adv_info *adv_instance;
3213 struct hci_request req;
3214 int err;
3215
3216 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3217 if (!adv_instance)
3218 return;
3219
3220 /* stop if current instance doesn't need to be changed */
3221 if (!(adv_instance->flags & flags))
3222 return;
3223
3224 cancel_adv_timeout(hdev);
3225
3226 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3227 if (!adv_instance)
3228 return;
3229
3230 hci_req_init(&req, hdev);
3231 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3232 true);
3233 if (err)
3234 return;
3235
3236 hci_req_run(&req, NULL);
3237}
3238
Marcel Holtmann1904a852015-01-11 13:50:44 -08003239static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003240{
3241 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003242 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003243
Marcel Holtmann181d6952020-05-06 09:57:47 +02003244 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003245
3246 hci_dev_lock(hdev);
3247
Johan Hedberg333ae952015-03-17 13:48:47 +02003248 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003249 if (!cmd)
3250 goto unlock;
3251
3252 cp = cmd->param;
3253
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003254 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003255 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3256 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003257 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003258 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3259 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003260
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003261 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3262 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3263 }
3264
Johan Hedberg13928972013-03-15 17:07:00 -05003265 mgmt_pending_remove(cmd);
3266
3267unlock:
3268 hci_dev_unlock(hdev);
3269}
3270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003271static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003272 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003273{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003274 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003275 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003276 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003277 int err;
3278
Marcel Holtmann181d6952020-05-06 09:57:47 +02003279 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003280
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003281 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003282
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003283 /* If the old values are the same as the new ones just return a
3284 * direct command complete event.
3285 */
3286 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3287 !memcmp(hdev->short_name, cp->short_name,
3288 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003289 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3290 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003291 goto failed;
3292 }
3293
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003294 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003295
Johan Hedbergb5235a62012-02-21 14:32:24 +02003296 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003297 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003298
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003299 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3300 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003301 if (err < 0)
3302 goto failed;
3303
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003304 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3305 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003306 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003307
Johan Hedbergb5235a62012-02-21 14:32:24 +02003308 goto failed;
3309 }
3310
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003311 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003312 if (!cmd) {
3313 err = -ENOMEM;
3314 goto failed;
3315 }
3316
Johan Hedberg13928972013-03-15 17:07:00 -05003317 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3318
Johan Hedberg890ea892013-03-15 17:06:52 -05003319 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003320
3321 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003322 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003323 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003324 }
3325
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003326 /* The name is stored in the scan response data and so
3327 * no need to udpate the advertising data here.
3328 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003329 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003330 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003331
Johan Hedberg13928972013-03-15 17:07:00 -05003332 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003333 if (err < 0)
3334 mgmt_pending_remove(cmd);
3335
3336failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003337 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003338 return err;
3339}
3340
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003341static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3342 u16 len)
3343{
3344 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003345 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003346 int err;
3347
Marcel Holtmann181d6952020-05-06 09:57:47 +02003348 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003349
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003350 if (!lmp_le_capable(hdev))
3351 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3352 MGMT_STATUS_NOT_SUPPORTED);
3353
Alain Michaud6613bab2020-01-22 19:47:44 +00003354 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003355
3356 hci_dev_lock(hdev);
3357
Alain Michaud6613bab2020-01-22 19:47:44 +00003358 if (hdev->appearance != appearance) {
3359 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003360
3361 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3362 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003363
3364 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003365 }
3366
3367 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3368 0);
3369
3370 hci_dev_unlock(hdev);
3371
3372 return err;
3373}
3374
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303375static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3376 void *data, u16 len)
3377{
3378 struct mgmt_rp_get_phy_confguration rp;
3379
Marcel Holtmann181d6952020-05-06 09:57:47 +02003380 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303381
3382 hci_dev_lock(hdev);
3383
3384 memset(&rp, 0, sizeof(rp));
3385
3386 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3387 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3388 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3389
3390 hci_dev_unlock(hdev);
3391
3392 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3393 &rp, sizeof(rp));
3394}
3395
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303396int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3397{
3398 struct mgmt_ev_phy_configuration_changed ev;
3399
3400 memset(&ev, 0, sizeof(ev));
3401
3402 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3403
3404 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3405 sizeof(ev), skip);
3406}
3407
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303408static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3409 u16 opcode, struct sk_buff *skb)
3410{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303411 struct mgmt_pending_cmd *cmd;
3412
Marcel Holtmann181d6952020-05-06 09:57:47 +02003413 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303414
3415 hci_dev_lock(hdev);
3416
3417 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3418 if (!cmd)
3419 goto unlock;
3420
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303421 if (status) {
3422 mgmt_cmd_status(cmd->sk, hdev->id,
3423 MGMT_OP_SET_PHY_CONFIGURATION,
3424 mgmt_status(status));
3425 } else {
3426 mgmt_cmd_complete(cmd->sk, hdev->id,
3427 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3428 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303429
3430 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303431 }
3432
3433 mgmt_pending_remove(cmd);
3434
3435unlock:
3436 hci_dev_unlock(hdev);
3437}
3438
3439static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3440 void *data, u16 len)
3441{
3442 struct mgmt_cp_set_phy_confguration *cp = data;
3443 struct hci_cp_le_set_default_phy cp_phy;
3444 struct mgmt_pending_cmd *cmd;
3445 struct hci_request req;
3446 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3447 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303448 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303449 int err;
3450
Marcel Holtmann181d6952020-05-06 09:57:47 +02003451 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303452
3453 configurable_phys = get_configurable_phys(hdev);
3454 supported_phys = get_supported_phys(hdev);
3455 selected_phys = __le32_to_cpu(cp->selected_phys);
3456
3457 if (selected_phys & ~supported_phys)
3458 return mgmt_cmd_status(sk, hdev->id,
3459 MGMT_OP_SET_PHY_CONFIGURATION,
3460 MGMT_STATUS_INVALID_PARAMS);
3461
3462 unconfigure_phys = supported_phys & ~configurable_phys;
3463
3464 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3465 return mgmt_cmd_status(sk, hdev->id,
3466 MGMT_OP_SET_PHY_CONFIGURATION,
3467 MGMT_STATUS_INVALID_PARAMS);
3468
3469 if (selected_phys == get_selected_phys(hdev))
3470 return mgmt_cmd_complete(sk, hdev->id,
3471 MGMT_OP_SET_PHY_CONFIGURATION,
3472 0, NULL, 0);
3473
3474 hci_dev_lock(hdev);
3475
3476 if (!hdev_is_powered(hdev)) {
3477 err = mgmt_cmd_status(sk, hdev->id,
3478 MGMT_OP_SET_PHY_CONFIGURATION,
3479 MGMT_STATUS_REJECTED);
3480 goto unlock;
3481 }
3482
3483 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3484 err = mgmt_cmd_status(sk, hdev->id,
3485 MGMT_OP_SET_PHY_CONFIGURATION,
3486 MGMT_STATUS_BUSY);
3487 goto unlock;
3488 }
3489
3490 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3491 pkt_type |= (HCI_DH3 | HCI_DM3);
3492 else
3493 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3494
3495 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3496 pkt_type |= (HCI_DH5 | HCI_DM5);
3497 else
3498 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3499
3500 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3501 pkt_type &= ~HCI_2DH1;
3502 else
3503 pkt_type |= HCI_2DH1;
3504
3505 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3506 pkt_type &= ~HCI_2DH3;
3507 else
3508 pkt_type |= HCI_2DH3;
3509
3510 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3511 pkt_type &= ~HCI_2DH5;
3512 else
3513 pkt_type |= HCI_2DH5;
3514
3515 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3516 pkt_type &= ~HCI_3DH1;
3517 else
3518 pkt_type |= HCI_3DH1;
3519
3520 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3521 pkt_type &= ~HCI_3DH3;
3522 else
3523 pkt_type |= HCI_3DH3;
3524
3525 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3526 pkt_type &= ~HCI_3DH5;
3527 else
3528 pkt_type |= HCI_3DH5;
3529
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303530 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303531 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303532 changed = true;
3533 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303534
3535 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3536 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303537 if (changed)
3538 mgmt_phy_configuration_changed(hdev, sk);
3539
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303540 err = mgmt_cmd_complete(sk, hdev->id,
3541 MGMT_OP_SET_PHY_CONFIGURATION,
3542 0, NULL, 0);
3543
3544 goto unlock;
3545 }
3546
3547 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3548 len);
3549 if (!cmd) {
3550 err = -ENOMEM;
3551 goto unlock;
3552 }
3553
3554 hci_req_init(&req, hdev);
3555
3556 memset(&cp_phy, 0, sizeof(cp_phy));
3557
3558 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3559 cp_phy.all_phys |= 0x01;
3560
3561 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3562 cp_phy.all_phys |= 0x02;
3563
3564 if (selected_phys & MGMT_PHY_LE_1M_TX)
3565 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3566
3567 if (selected_phys & MGMT_PHY_LE_2M_TX)
3568 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3569
3570 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3571 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3572
3573 if (selected_phys & MGMT_PHY_LE_1M_RX)
3574 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3575
3576 if (selected_phys & MGMT_PHY_LE_2M_RX)
3577 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3578
3579 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3580 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3581
3582 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3583
3584 err = hci_req_run_skb(&req, set_default_phy_complete);
3585 if (err < 0)
3586 mgmt_pending_remove(cmd);
3587
3588unlock:
3589 hci_dev_unlock(hdev);
3590
3591 return err;
3592}
3593
Alain Michaud600a8742020-01-07 00:43:17 +00003594static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3595 u16 len)
3596{
3597 int err = MGMT_STATUS_SUCCESS;
3598 struct mgmt_cp_set_blocked_keys *keys = data;
3599 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3600 sizeof(struct mgmt_blocked_key_info));
3601 u16 key_count, expected_len;
3602 int i;
3603
Marcel Holtmann181d6952020-05-06 09:57:47 +02003604 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003605
3606 key_count = __le16_to_cpu(keys->key_count);
3607 if (key_count > max_key_count) {
3608 bt_dev_err(hdev, "too big key_count value %u", key_count);
3609 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3610 MGMT_STATUS_INVALID_PARAMS);
3611 }
3612
3613 expected_len = struct_size(keys, keys, key_count);
3614 if (expected_len != len) {
3615 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3616 expected_len, len);
3617 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3618 MGMT_STATUS_INVALID_PARAMS);
3619 }
3620
3621 hci_dev_lock(hdev);
3622
3623 hci_blocked_keys_clear(hdev);
3624
3625 for (i = 0; i < keys->key_count; ++i) {
3626 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3627
3628 if (!b) {
3629 err = MGMT_STATUS_NO_RESOURCES;
3630 break;
3631 }
3632
3633 b->type = keys->keys[i].type;
3634 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3635 list_add_rcu(&b->list, &hdev->blocked_keys);
3636 }
3637 hci_dev_unlock(hdev);
3638
3639 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3640 err, NULL, 0);
3641}
3642
Alain Michaud00bce3f2020-03-05 16:14:59 +00003643static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3644 void *data, u16 len)
3645{
3646 struct mgmt_mode *cp = data;
3647 int err;
3648 bool changed = false;
3649
Marcel Holtmann181d6952020-05-06 09:57:47 +02003650 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003651
3652 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3653 return mgmt_cmd_status(sk, hdev->id,
3654 MGMT_OP_SET_WIDEBAND_SPEECH,
3655 MGMT_STATUS_NOT_SUPPORTED);
3656
3657 if (cp->val != 0x00 && cp->val != 0x01)
3658 return mgmt_cmd_status(sk, hdev->id,
3659 MGMT_OP_SET_WIDEBAND_SPEECH,
3660 MGMT_STATUS_INVALID_PARAMS);
3661
3662 hci_dev_lock(hdev);
3663
3664 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3665 err = mgmt_cmd_status(sk, hdev->id,
3666 MGMT_OP_SET_WIDEBAND_SPEECH,
3667 MGMT_STATUS_BUSY);
3668 goto unlock;
3669 }
3670
3671 if (hdev_is_powered(hdev) &&
3672 !!cp->val != hci_dev_test_flag(hdev,
3673 HCI_WIDEBAND_SPEECH_ENABLED)) {
3674 err = mgmt_cmd_status(sk, hdev->id,
3675 MGMT_OP_SET_WIDEBAND_SPEECH,
3676 MGMT_STATUS_REJECTED);
3677 goto unlock;
3678 }
3679
3680 if (cp->val)
3681 changed = !hci_dev_test_and_set_flag(hdev,
3682 HCI_WIDEBAND_SPEECH_ENABLED);
3683 else
3684 changed = hci_dev_test_and_clear_flag(hdev,
3685 HCI_WIDEBAND_SPEECH_ENABLED);
3686
3687 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3688 if (err < 0)
3689 goto unlock;
3690
3691 if (changed)
3692 err = new_settings(hdev, sk);
3693
3694unlock:
3695 hci_dev_unlock(hdev);
3696 return err;
3697}
3698
Marcel Holtmannbc292252020-04-03 21:44:05 +02003699static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3700 void *data, u16 data_len)
3701{
3702 char buf[16];
3703 struct mgmt_rp_read_security_info *rp = (void *)buf;
3704 u16 sec_len = 0;
3705 u8 flags = 0;
3706
3707 bt_dev_dbg(hdev, "sock %p", sk);
3708
3709 memset(&buf, 0, sizeof(buf));
3710
3711 hci_dev_lock(hdev);
3712
3713 /* When the Read Simple Pairing Options command is supported, then
3714 * the remote public key validation is supported.
3715 */
3716 if (hdev->commands[41] & 0x08)
3717 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3718
3719 flags |= 0x02; /* Remote public key validation (LE) */
3720
3721 /* When the Read Encryption Key Size command is supported, then the
3722 * encryption key size is enforced.
3723 */
3724 if (hdev->commands[20] & 0x10)
3725 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3726
3727 flags |= 0x08; /* Encryption key size enforcement (LE) */
3728
3729 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3730
3731 /* When the Read Simple Pairing Options command is supported, then
3732 * also max encryption key size information is provided.
3733 */
3734 if (hdev->commands[41] & 0x08)
3735 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3736 hdev->max_enc_key_size);
3737
3738 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3739
3740 rp->sec_len = cpu_to_le16(sec_len);
3741
3742 hci_dev_unlock(hdev);
3743
3744 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3745 rp, sizeof(*rp) + sec_len);
3746}
3747
Marcel Holtmanne625e502020-05-06 09:57:52 +02003748#ifdef CONFIG_BT_FEATURE_DEBUG
3749/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3750static const u8 debug_uuid[16] = {
3751 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3752 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3753};
3754#endif
3755
Alain Michaud15d8ce02020-07-07 17:46:06 +02003756/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
3757static const u8 simult_central_periph_uuid[16] = {
3758 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
3759 0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
3760};
3761
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003762static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3763 void *data, u16 data_len)
3764{
Alain Michaud15d8ce02020-07-07 17:46:06 +02003765 char buf[44];
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003766 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3767 u16 idx = 0;
Alain Michaud15d8ce02020-07-07 17:46:06 +02003768 u32 flags;
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003769
3770 bt_dev_dbg(hdev, "sock %p", sk);
3771
3772 memset(&buf, 0, sizeof(buf));
3773
Marcel Holtmanne625e502020-05-06 09:57:52 +02003774#ifdef CONFIG_BT_FEATURE_DEBUG
3775 if (!hdev) {
Alain Michaud15d8ce02020-07-07 17:46:06 +02003776 flags = bt_dbg_get() ? BIT(0) : 0;
Marcel Holtmanne625e502020-05-06 09:57:52 +02003777
3778 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3779 rp->features[idx].flags = cpu_to_le32(flags);
3780 idx++;
3781 }
3782#endif
3783
Alain Michaud15d8ce02020-07-07 17:46:06 +02003784 if (hdev) {
3785 if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
3786 (hdev->le_states[4] & 0x08) && /* Central */
3787 (hdev->le_states[4] & 0x40) && /* Peripheral */
3788 (hdev->le_states[3] & 0x10)) /* Simultaneous */
3789 flags = BIT(0);
3790 else
3791 flags = 0;
3792
3793 memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
3794 rp->features[idx].flags = cpu_to_le32(flags);
3795 idx++;
3796 }
3797
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003798 rp->feature_count = cpu_to_le16(idx);
3799
3800 /* After reading the experimental features information, enable
3801 * the events to update client on any future change.
3802 */
3803 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3804
3805 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3806 MGMT_OP_READ_EXP_FEATURES_INFO,
3807 0, rp, sizeof(*rp) + (20 * idx));
3808}
3809
Marcel Holtmanne625e502020-05-06 09:57:52 +02003810#ifdef CONFIG_BT_FEATURE_DEBUG
3811static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3812{
3813 struct mgmt_ev_exp_feature_changed ev;
3814
3815 memset(&ev, 0, sizeof(ev));
3816 memcpy(ev.uuid, debug_uuid, 16);
3817 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3818
3819 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3820 &ev, sizeof(ev),
3821 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3822}
3823#endif
3824
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003825static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3826 void *data, u16 data_len)
3827{
3828 struct mgmt_cp_set_exp_feature *cp = data;
3829 struct mgmt_rp_set_exp_feature rp;
3830
3831 bt_dev_dbg(hdev, "sock %p", sk);
3832
3833 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3834 memset(rp.uuid, 0, 16);
3835 rp.flags = cpu_to_le32(0);
3836
Marcel Holtmanne625e502020-05-06 09:57:52 +02003837#ifdef CONFIG_BT_FEATURE_DEBUG
3838 if (!hdev) {
3839 bool changed = bt_dbg_get();
3840
3841 bt_dbg_set(false);
3842
3843 if (changed)
3844 exp_debug_feature_changed(false, sk);
3845 }
3846#endif
3847
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003848 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3849
3850 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3851 MGMT_OP_SET_EXP_FEATURE, 0,
3852 &rp, sizeof(rp));
3853 }
3854
Marcel Holtmanne625e502020-05-06 09:57:52 +02003855#ifdef CONFIG_BT_FEATURE_DEBUG
3856 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3857 bool val, changed;
3858 int err;
3859
3860 /* Command requires to use the non-controller index */
3861 if (hdev)
3862 return mgmt_cmd_status(sk, hdev->id,
3863 MGMT_OP_SET_EXP_FEATURE,
3864 MGMT_STATUS_INVALID_INDEX);
3865
3866 /* Parameters are limited to a single octet */
3867 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3868 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3869 MGMT_OP_SET_EXP_FEATURE,
3870 MGMT_STATUS_INVALID_PARAMS);
3871
3872 /* Only boolean on/off is supported */
3873 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3874 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3875 MGMT_OP_SET_EXP_FEATURE,
3876 MGMT_STATUS_INVALID_PARAMS);
3877
3878 val = !!cp->param[0];
3879 changed = val ? !bt_dbg_get() : bt_dbg_get();
3880 bt_dbg_set(val);
3881
3882 memcpy(rp.uuid, debug_uuid, 16);
3883 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3884
3885 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3886
3887 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3888 MGMT_OP_SET_EXP_FEATURE, 0,
3889 &rp, sizeof(rp));
3890
3891 if (changed)
3892 exp_debug_feature_changed(val, sk);
3893
3894 return err;
3895 }
3896#endif
3897
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003898 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3899 MGMT_OP_SET_EXP_FEATURE,
3900 MGMT_STATUS_NOT_SUPPORTED);
3901}
3902
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003903#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
3904
3905static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3906 u16 data_len)
3907{
3908 struct mgmt_cp_get_device_flags *cp = data;
3909 struct mgmt_rp_get_device_flags rp;
3910 struct bdaddr_list_with_flags *br_params;
3911 struct hci_conn_params *params;
3912 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3913 u32 current_flags = 0;
3914 u8 status = MGMT_STATUS_INVALID_PARAMS;
3915
3916 bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
3917 &cp->addr.bdaddr, cp->addr.type);
3918
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07003919 hci_dev_lock(hdev);
3920
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003921 if (cp->addr.type == BDADDR_BREDR) {
3922 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3923 &cp->addr.bdaddr,
3924 cp->addr.type);
3925 if (!br_params)
3926 goto done;
3927
3928 current_flags = br_params->current_flags;
3929 } else {
3930 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
3931 le_addr_type(cp->addr.type));
3932
3933 if (!params)
3934 goto done;
3935
3936 current_flags = params->current_flags;
3937 }
3938
3939 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3940 rp.addr.type = cp->addr.type;
3941 rp.supported_flags = cpu_to_le32(supported_flags);
3942 rp.current_flags = cpu_to_le32(current_flags);
3943
3944 status = MGMT_STATUS_SUCCESS;
3945
3946done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07003947 hci_dev_unlock(hdev);
3948
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003949 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
3950 &rp, sizeof(rp));
3951}
3952
3953static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
3954 bdaddr_t *bdaddr, u8 bdaddr_type,
3955 u32 supported_flags, u32 current_flags)
3956{
3957 struct mgmt_ev_device_flags_changed ev;
3958
3959 bacpy(&ev.addr.bdaddr, bdaddr);
3960 ev.addr.type = bdaddr_type;
3961 ev.supported_flags = cpu_to_le32(supported_flags);
3962 ev.current_flags = cpu_to_le32(current_flags);
3963
3964 mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
3965}
3966
3967static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
3968 u16 len)
3969{
3970 struct mgmt_cp_set_device_flags *cp = data;
3971 struct bdaddr_list_with_flags *br_params;
3972 struct hci_conn_params *params;
3973 u8 status = MGMT_STATUS_INVALID_PARAMS;
3974 u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
3975 u32 current_flags = __le32_to_cpu(cp->current_flags);
3976
3977 bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
3978 &cp->addr.bdaddr, cp->addr.type,
3979 __le32_to_cpu(current_flags));
3980
3981 if ((supported_flags | current_flags) != supported_flags) {
3982 bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
3983 current_flags, supported_flags);
3984 goto done;
3985 }
3986
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07003987 hci_dev_lock(hdev);
3988
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02003989 if (cp->addr.type == BDADDR_BREDR) {
3990 br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
3991 &cp->addr.bdaddr,
3992 cp->addr.type);
3993
3994 if (br_params) {
3995 br_params->current_flags = current_flags;
3996 status = MGMT_STATUS_SUCCESS;
3997 } else {
3998 bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
3999 &cp->addr.bdaddr, cp->addr.type);
4000 }
4001 } else {
4002 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
4003 le_addr_type(cp->addr.type));
4004 if (params) {
4005 params->current_flags = current_flags;
4006 status = MGMT_STATUS_SUCCESS;
4007 } else {
4008 bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
4009 &cp->addr.bdaddr,
4010 le_addr_type(cp->addr.type));
4011 }
4012 }
4013
4014done:
Abhishek Pandit-Subedi3ca33e32020-06-19 17:10:24 -07004015 hci_dev_unlock(hdev);
4016
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02004017 if (status == MGMT_STATUS_SUCCESS)
4018 device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
4019 supported_flags, current_flags);
4020
4021 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
4022 &cp->addr, sizeof(cp->addr));
4023}
4024
Miao-chen Choub52729f2020-06-17 16:39:16 +02004025static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
4026 u16 handle)
4027{
4028 struct mgmt_ev_adv_monitor_added ev;
4029
4030 ev.monitor_handle = cpu_to_le16(handle);
4031
4032 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
4033}
4034
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004035static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
4036 u16 handle)
4037{
4038 struct mgmt_ev_adv_monitor_added ev;
4039
4040 ev.monitor_handle = cpu_to_le16(handle);
4041
4042 mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
4043}
4044
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02004045static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
4046 void *data, u16 len)
4047{
4048 struct adv_monitor *monitor = NULL;
4049 struct mgmt_rp_read_adv_monitor_features *rp = NULL;
4050 int handle;
4051 size_t rp_size = 0;
4052 __u32 supported = 0;
4053 __u16 num_handles = 0;
4054 __u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
4055
4056 BT_DBG("request for %s", hdev->name);
4057
4058 hci_dev_lock(hdev);
4059
4060 if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
4061 supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
4062
4063 idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
4064 handles[num_handles++] = monitor->handle;
4065 }
4066
4067 hci_dev_unlock(hdev);
4068
4069 rp_size = sizeof(*rp) + (num_handles * sizeof(u16));
4070 rp = kmalloc(rp_size, GFP_KERNEL);
4071 if (!rp)
4072 return -ENOMEM;
4073
4074 /* Once controller-based monitoring is in place, the enabled_features
4075 * should reflect the use.
4076 */
4077 rp->supported_features = cpu_to_le32(supported);
4078 rp->enabled_features = 0;
4079 rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
4080 rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
4081 rp->num_handles = cpu_to_le16(num_handles);
4082 if (num_handles)
4083 memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
4084
4085 return mgmt_cmd_complete(sk, hdev->id,
4086 MGMT_OP_READ_ADV_MONITOR_FEATURES,
4087 MGMT_STATUS_SUCCESS, rp, rp_size);
4088}
4089
Miao-chen Choub1395532020-06-17 16:39:14 +02004090static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4091 void *data, u16 len)
4092{
4093 struct mgmt_cp_add_adv_patterns_monitor *cp = data;
4094 struct mgmt_rp_add_adv_patterns_monitor rp;
4095 struct adv_monitor *m = NULL;
4096 struct adv_pattern *p = NULL;
Miao-chen Choub52729f2020-06-17 16:39:16 +02004097 unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
Miao-chen Choub1395532020-06-17 16:39:14 +02004098 __u8 cp_ofst = 0, cp_len = 0;
Miao-chen Choub1395532020-06-17 16:39:14 +02004099 int err, i;
4100
4101 BT_DBG("request for %s", hdev->name);
4102
4103 if (len <= sizeof(*cp) || cp->pattern_count == 0) {
4104 err = mgmt_cmd_status(sk, hdev->id,
4105 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4106 MGMT_STATUS_INVALID_PARAMS);
4107 goto failed;
4108 }
4109
4110 m = kmalloc(sizeof(*m), GFP_KERNEL);
4111 if (!m) {
4112 err = -ENOMEM;
4113 goto failed;
4114 }
4115
4116 INIT_LIST_HEAD(&m->patterns);
4117 m->active = false;
4118
4119 for (i = 0; i < cp->pattern_count; i++) {
4120 if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
4121 err = mgmt_cmd_status(sk, hdev->id,
4122 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4123 MGMT_STATUS_INVALID_PARAMS);
4124 goto failed;
4125 }
4126
4127 cp_ofst = cp->patterns[i].offset;
4128 cp_len = cp->patterns[i].length;
4129 if (cp_ofst >= HCI_MAX_AD_LENGTH ||
4130 cp_len > HCI_MAX_AD_LENGTH ||
4131 (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
4132 err = mgmt_cmd_status(sk, hdev->id,
4133 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4134 MGMT_STATUS_INVALID_PARAMS);
4135 goto failed;
4136 }
4137
4138 p = kmalloc(sizeof(*p), GFP_KERNEL);
4139 if (!p) {
4140 err = -ENOMEM;
4141 goto failed;
4142 }
4143
4144 p->ad_type = cp->patterns[i].ad_type;
4145 p->offset = cp->patterns[i].offset;
4146 p->length = cp->patterns[i].length;
4147 memcpy(p->value, cp->patterns[i].value, p->length);
4148
4149 INIT_LIST_HEAD(&p->list);
4150 list_add(&p->list, &m->patterns);
4151 }
4152
4153 if (mp_cnt != cp->pattern_count) {
4154 err = mgmt_cmd_status(sk, hdev->id,
4155 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4156 MGMT_STATUS_INVALID_PARAMS);
4157 goto failed;
4158 }
4159
4160 hci_dev_lock(hdev);
4161
Miao-chen Choub52729f2020-06-17 16:39:16 +02004162 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4163
Miao-chen Choub1395532020-06-17 16:39:14 +02004164 err = hci_add_adv_monitor(hdev, m);
4165 if (err) {
4166 if (err == -ENOSPC) {
4167 mgmt_cmd_status(sk, hdev->id,
4168 MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4169 MGMT_STATUS_NO_RESOURCES);
4170 }
4171 goto unlock;
4172 }
4173
Miao-chen Choub52729f2020-06-17 16:39:16 +02004174 if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt)
4175 mgmt_adv_monitor_added(sk, hdev, m->handle);
4176
Miao-chen Choub1395532020-06-17 16:39:14 +02004177 hci_dev_unlock(hdev);
4178
4179 rp.monitor_handle = cpu_to_le16(m->handle);
4180
4181 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
4182 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4183
4184unlock:
4185 hci_dev_unlock(hdev);
4186
4187failed:
4188 hci_free_adv_monitor(m);
4189 return err;
4190}
4191
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004192static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
4193 void *data, u16 len)
4194{
4195 struct mgmt_cp_remove_adv_monitor *cp = data;
4196 struct mgmt_rp_remove_adv_monitor rp;
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004197 unsigned int prev_adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004198 u16 handle;
4199 int err;
4200
4201 BT_DBG("request for %s", hdev->name);
4202
4203 hci_dev_lock(hdev);
4204
4205 handle = __le16_to_cpu(cp->monitor_handle);
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004206 prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004207
4208 err = hci_remove_adv_monitor(hdev, handle);
4209 if (err == -ENOENT) {
4210 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4211 MGMT_STATUS_INVALID_INDEX);
4212 goto unlock;
4213 }
4214
Miao-chen Choucdde92e2020-06-17 16:39:17 +02004215 if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt)
4216 mgmt_adv_monitor_removed(sk, hdev, handle);
4217
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02004218 hci_dev_unlock(hdev);
4219
4220 rp.monitor_handle = cp->monitor_handle;
4221
4222 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4223 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4224
4225unlock:
4226 hci_dev_unlock(hdev);
4227 return err;
4228}
4229
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004230static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
4231 u16 opcode, struct sk_buff *skb)
4232{
4233 struct mgmt_rp_read_local_oob_data mgmt_rp;
4234 size_t rp_size = sizeof(mgmt_rp);
4235 struct mgmt_pending_cmd *cmd;
4236
Marcel Holtmann181d6952020-05-06 09:57:47 +02004237 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004238
4239 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
4240 if (!cmd)
4241 return;
4242
4243 if (status || !skb) {
4244 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4245 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
4246 goto remove;
4247 }
4248
4249 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
4250
4251 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
4252 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
4253
4254 if (skb->len < sizeof(*rp)) {
4255 mgmt_cmd_status(cmd->sk, hdev->id,
4256 MGMT_OP_READ_LOCAL_OOB_DATA,
4257 MGMT_STATUS_FAILED);
4258 goto remove;
4259 }
4260
4261 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
4262 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
4263
4264 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
4265 } else {
4266 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
4267
4268 if (skb->len < sizeof(*rp)) {
4269 mgmt_cmd_status(cmd->sk, hdev->id,
4270 MGMT_OP_READ_LOCAL_OOB_DATA,
4271 MGMT_STATUS_FAILED);
4272 goto remove;
4273 }
4274
4275 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
4276 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
4277
4278 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
4279 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
4280 }
4281
4282 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4283 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
4284
4285remove:
4286 mgmt_pending_remove(cmd);
4287}
4288
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004289static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004290 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01004291{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004292 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004293 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01004294 int err;
4295
Marcel Holtmann181d6952020-05-06 09:57:47 +02004296 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01004297
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004298 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004299
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004300 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004301 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4302 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004303 goto unlock;
4304 }
4305
Andre Guedes9a1a1992012-07-24 15:03:48 -03004306 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004307 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4308 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01004309 goto unlock;
4310 }
4311
Johan Hedberg333ae952015-03-17 13:48:47 +02004312 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004313 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4314 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01004315 goto unlock;
4316 }
4317
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004318 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01004319 if (!cmd) {
4320 err = -ENOMEM;
4321 goto unlock;
4322 }
4323
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004324 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08004325
Johan Hedberg1b9441f2015-04-02 13:41:13 +03004326 if (bredr_sc_enabled(hdev))
4327 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
4328 else
4329 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
4330
4331 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01004332 if (err < 0)
4333 mgmt_pending_remove(cmd);
4334
4335unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004336 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004337 return err;
4338}
4339
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004340static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004341 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004342{
Johan Hedberg5d57e792015-01-23 10:10:38 +02004343 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01004344 int err;
4345
Marcel Holtmann181d6952020-05-06 09:57:47 +02004346 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004347
Johan Hedberg5d57e792015-01-23 10:10:38 +02004348 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004349 return mgmt_cmd_complete(sk, hdev->id,
4350 MGMT_OP_ADD_REMOTE_OOB_DATA,
4351 MGMT_STATUS_INVALID_PARAMS,
4352 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02004353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004354 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004355
Marcel Holtmannec109112014-01-10 02:07:30 -08004356 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
4357 struct mgmt_cp_add_remote_oob_data *cp = data;
4358 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004359
Johan Hedbergc19a4952014-11-17 20:52:19 +02004360 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004361 err = mgmt_cmd_complete(sk, hdev->id,
4362 MGMT_OP_ADD_REMOTE_OOB_DATA,
4363 MGMT_STATUS_INVALID_PARAMS,
4364 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004365 goto unlock;
4366 }
4367
Marcel Holtmannec109112014-01-10 02:07:30 -08004368 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01004369 cp->addr.type, cp->hash,
4370 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004371 if (err < 0)
4372 status = MGMT_STATUS_FAILED;
4373 else
4374 status = MGMT_STATUS_SUCCESS;
4375
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004376 err = mgmt_cmd_complete(sk, hdev->id,
4377 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4378 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004379 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4380 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004381 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004382 u8 status;
4383
Johan Hedberg86df9202014-10-26 20:52:27 +01004384 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004385 /* Enforce zero-valued 192-bit parameters as
4386 * long as legacy SMP OOB isn't implemented.
4387 */
4388 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4389 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004390 err = mgmt_cmd_complete(sk, hdev->id,
4391 MGMT_OP_ADD_REMOTE_OOB_DATA,
4392 MGMT_STATUS_INVALID_PARAMS,
4393 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004394 goto unlock;
4395 }
4396
Johan Hedberg86df9202014-10-26 20:52:27 +01004397 rand192 = NULL;
4398 hash192 = NULL;
4399 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004400 /* In case one of the P-192 values is set to zero,
4401 * then just disable OOB data for P-192.
4402 */
4403 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4404 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4405 rand192 = NULL;
4406 hash192 = NULL;
4407 } else {
4408 rand192 = cp->rand192;
4409 hash192 = cp->hash192;
4410 }
4411 }
4412
4413 /* In case one of the P-256 values is set to zero, then just
4414 * disable OOB data for P-256.
4415 */
4416 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4417 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4418 rand256 = NULL;
4419 hash256 = NULL;
4420 } else {
4421 rand256 = cp->rand256;
4422 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004423 }
4424
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004425 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004426 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004427 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004428 if (err < 0)
4429 status = MGMT_STATUS_FAILED;
4430 else
4431 status = MGMT_STATUS_SUCCESS;
4432
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004433 err = mgmt_cmd_complete(sk, hdev->id,
4434 MGMT_OP_ADD_REMOTE_OOB_DATA,
4435 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004436 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004437 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4438 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004439 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4440 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004441 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004442
Johan Hedbergc19a4952014-11-17 20:52:19 +02004443unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004444 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004445 return err;
4446}
4447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004448static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004449 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004450{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004451 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004452 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004453 int err;
4454
Marcel Holtmann181d6952020-05-06 09:57:47 +02004455 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004456
Johan Hedbergc19a4952014-11-17 20:52:19 +02004457 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004458 return mgmt_cmd_complete(sk, hdev->id,
4459 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4460 MGMT_STATUS_INVALID_PARAMS,
4461 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004463 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004464
Johan Hedbergeedbd582014-11-15 09:34:23 +02004465 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4466 hci_remote_oob_data_clear(hdev);
4467 status = MGMT_STATUS_SUCCESS;
4468 goto done;
4469 }
4470
Johan Hedberg6928a922014-10-26 20:46:09 +01004471 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004472 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004473 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004474 else
Szymon Janca6785be2012-12-13 15:11:21 +01004475 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004476
Johan Hedbergeedbd582014-11-15 09:34:23 +02004477done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004478 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4479 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004480
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004481 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004482 return err;
4483}
4484
Johan Hedberge68f0722015-11-11 08:30:30 +02004485void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004486{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004487 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004488
Marcel Holtmann181d6952020-05-06 09:57:47 +02004489 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004490
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004491 hci_dev_lock(hdev);
4492
Johan Hedberg333ae952015-03-17 13:48:47 +02004493 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004494 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004495 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004496
Johan Hedberg78b781c2016-01-05 13:19:32 +02004497 if (!cmd)
4498 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4499
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004500 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004501 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004502 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004503 }
4504
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004505 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004506
4507 /* Handle suspend notifier */
4508 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4509 hdev->suspend_tasks)) {
4510 bt_dev_dbg(hdev, "Unpaused discovery");
4511 wake_up(&hdev->suspend_wait_q);
4512 }
Andre Guedes7c307722013-04-30 15:29:28 -03004513}
4514
Johan Hedberg591752a2015-11-11 08:11:24 +02004515static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4516 uint8_t *mgmt_status)
4517{
4518 switch (type) {
4519 case DISCOV_TYPE_LE:
4520 *mgmt_status = mgmt_le_support(hdev);
4521 if (*mgmt_status)
4522 return false;
4523 break;
4524 case DISCOV_TYPE_INTERLEAVED:
4525 *mgmt_status = mgmt_le_support(hdev);
4526 if (*mgmt_status)
4527 return false;
4528 /* Intentional fall-through */
4529 case DISCOV_TYPE_BREDR:
4530 *mgmt_status = mgmt_bredr_support(hdev);
4531 if (*mgmt_status)
4532 return false;
4533 break;
4534 default:
4535 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4536 return false;
4537 }
4538
4539 return true;
4540}
4541
Johan Hedberg78b781c2016-01-05 13:19:32 +02004542static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4543 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004544{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004545 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004546 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004547 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004548 int err;
4549
Marcel Holtmann181d6952020-05-06 09:57:47 +02004550 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004552 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004553
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004554 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004555 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004556 MGMT_STATUS_NOT_POWERED,
4557 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004558 goto failed;
4559 }
4560
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004561 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004562 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004563 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4564 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004565 goto failed;
4566 }
4567
Johan Hedberg591752a2015-11-11 08:11:24 +02004568 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004569 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4570 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004571 goto failed;
4572 }
4573
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004574 /* Can't start discovery when it is paused */
4575 if (hdev->discovery_paused) {
4576 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4577 &cp->type, sizeof(cp->type));
4578 goto failed;
4579 }
4580
Marcel Holtmann22078802014-12-05 11:45:22 +01004581 /* Clear the discovery filter first to free any previously
4582 * allocated memory for the UUID list.
4583 */
4584 hci_discovery_filter_clear(hdev);
4585
Andre Guedes4aab14e2012-02-17 20:39:36 -03004586 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004587 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004588 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4589 hdev->discovery.limited = true;
4590 else
4591 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004592
Johan Hedberg78b781c2016-01-05 13:19:32 +02004593 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004594 if (!cmd) {
4595 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004596 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004597 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004598
Johan Hedberge68f0722015-11-11 08:30:30 +02004599 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004600
4601 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004602 queue_work(hdev->req_workqueue, &hdev->discov_update);
4603 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004604
4605failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004606 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004607 return err;
4608}
4609
Johan Hedberg78b781c2016-01-05 13:19:32 +02004610static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4611 void *data, u16 len)
4612{
4613 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4614 data, len);
4615}
4616
4617static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4618 void *data, u16 len)
4619{
4620 return start_discovery_internal(sk, hdev,
4621 MGMT_OP_START_LIMITED_DISCOVERY,
4622 data, len);
4623}
4624
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004625static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4626 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004627{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004628 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4629 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004630}
4631
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004632static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4633 void *data, u16 len)
4634{
4635 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004636 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004637 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4638 u16 uuid_count, expected_len;
4639 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004640 int err;
4641
Marcel Holtmann181d6952020-05-06 09:57:47 +02004642 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004643
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004644 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004645
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004646 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004647 err = mgmt_cmd_complete(sk, hdev->id,
4648 MGMT_OP_START_SERVICE_DISCOVERY,
4649 MGMT_STATUS_NOT_POWERED,
4650 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004651 goto failed;
4652 }
4653
4654 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004655 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004656 err = mgmt_cmd_complete(sk, hdev->id,
4657 MGMT_OP_START_SERVICE_DISCOVERY,
4658 MGMT_STATUS_BUSY, &cp->type,
4659 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004660 goto failed;
4661 }
4662
4663 uuid_count = __le16_to_cpu(cp->uuid_count);
4664 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004665 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4666 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004667 err = mgmt_cmd_complete(sk, hdev->id,
4668 MGMT_OP_START_SERVICE_DISCOVERY,
4669 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4670 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004671 goto failed;
4672 }
4673
4674 expected_len = sizeof(*cp) + uuid_count * 16;
4675 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004676 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4677 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004678 err = mgmt_cmd_complete(sk, hdev->id,
4679 MGMT_OP_START_SERVICE_DISCOVERY,
4680 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4681 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004682 goto failed;
4683 }
4684
Johan Hedberg591752a2015-11-11 08:11:24 +02004685 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4686 err = mgmt_cmd_complete(sk, hdev->id,
4687 MGMT_OP_START_SERVICE_DISCOVERY,
4688 status, &cp->type, sizeof(cp->type));
4689 goto failed;
4690 }
4691
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004692 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004693 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004694 if (!cmd) {
4695 err = -ENOMEM;
4696 goto failed;
4697 }
4698
Johan Hedberg2922a942014-12-05 13:36:06 +02004699 cmd->cmd_complete = service_discovery_cmd_complete;
4700
Marcel Holtmann22078802014-12-05 11:45:22 +01004701 /* Clear the discovery filter first to free any previously
4702 * allocated memory for the UUID list.
4703 */
4704 hci_discovery_filter_clear(hdev);
4705
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004706 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004707 hdev->discovery.type = cp->type;
4708 hdev->discovery.rssi = cp->rssi;
4709 hdev->discovery.uuid_count = uuid_count;
4710
4711 if (uuid_count > 0) {
4712 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4713 GFP_KERNEL);
4714 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004715 err = mgmt_cmd_complete(sk, hdev->id,
4716 MGMT_OP_START_SERVICE_DISCOVERY,
4717 MGMT_STATUS_FAILED,
4718 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004719 mgmt_pending_remove(cmd);
4720 goto failed;
4721 }
4722 }
4723
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004724 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004725 queue_work(hdev->req_workqueue, &hdev->discov_update);
4726 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004727
4728failed:
4729 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004730 return err;
4731}
4732
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004733void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004734{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004735 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004736
Marcel Holtmann181d6952020-05-06 09:57:47 +02004737 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004738
4739 hci_dev_lock(hdev);
4740
Johan Hedberg333ae952015-03-17 13:48:47 +02004741 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004742 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004743 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004744 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004745 }
4746
Andre Guedes0e05bba2013-04-30 15:29:33 -03004747 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004748
4749 /* Handle suspend notifier */
4750 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4751 bt_dev_dbg(hdev, "Paused discovery");
4752 wake_up(&hdev->suspend_wait_q);
4753 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004754}
4755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004756static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004757 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004758{
Johan Hedbergd9306502012-02-20 23:25:18 +02004759 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004760 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004761 int err;
4762
Marcel Holtmann181d6952020-05-06 09:57:47 +02004763 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004765 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004766
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004767 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004768 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4769 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4770 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004771 goto unlock;
4772 }
4773
4774 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004775 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4776 MGMT_STATUS_INVALID_PARAMS,
4777 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004778 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004779 }
4780
Johan Hedberg2922a942014-12-05 13:36:06 +02004781 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004782 if (!cmd) {
4783 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004784 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004785 }
4786
Johan Hedberg2922a942014-12-05 13:36:06 +02004787 cmd->cmd_complete = generic_cmd_complete;
4788
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004789 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4790 queue_work(hdev->req_workqueue, &hdev->discov_update);
4791 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004792
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004793unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004794 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004795 return err;
4796}
4797
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004798static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004799 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004800{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004801 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004802 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004803 int err;
4804
Marcel Holtmann181d6952020-05-06 09:57:47 +02004805 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004806
Johan Hedberg561aafb2012-01-04 13:31:59 +02004807 hci_dev_lock(hdev);
4808
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004809 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004810 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4811 MGMT_STATUS_FAILED, &cp->addr,
4812 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004813 goto failed;
4814 }
4815
Johan Hedberga198e7b2012-02-17 14:27:06 +02004816 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004817 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004818 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4819 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4820 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004821 goto failed;
4822 }
4823
4824 if (cp->name_known) {
4825 e->name_state = NAME_KNOWN;
4826 list_del(&e->list);
4827 } else {
4828 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004829 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004830 }
4831
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004832 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4833 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004834
4835failed:
4836 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004837 return err;
4838}
4839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004840static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004841 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004843 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004844 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004845 int err;
4846
Marcel Holtmann181d6952020-05-06 09:57:47 +02004847 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004848
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004849 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004850 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4851 MGMT_STATUS_INVALID_PARAMS,
4852 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004853
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004854 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004855
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004856 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4857 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004858 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004859 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004860 goto done;
4861 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004862
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004863 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4864 sk);
4865 status = MGMT_STATUS_SUCCESS;
4866
4867done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004868 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4869 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004871 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004872
4873 return err;
4874}
4875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004876static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004877 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004878{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004879 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004880 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004881 int err;
4882
Marcel Holtmann181d6952020-05-06 09:57:47 +02004883 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004884
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004885 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004886 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4887 MGMT_STATUS_INVALID_PARAMS,
4888 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004890 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004891
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004892 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4893 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004894 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004895 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004896 goto done;
4897 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004898
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004899 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4900 sk);
4901 status = MGMT_STATUS_SUCCESS;
4902
4903done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004904 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4905 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004906
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004907 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004908
4909 return err;
4910}
4911
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004912static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4913 u16 len)
4914{
4915 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004916 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004917 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004918 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004919
Marcel Holtmann181d6952020-05-06 09:57:47 +02004920 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004921
Szymon Jancc72d4b82012-03-16 16:02:57 +01004922 source = __le16_to_cpu(cp->source);
4923
4924 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4926 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004927
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004928 hci_dev_lock(hdev);
4929
Szymon Jancc72d4b82012-03-16 16:02:57 +01004930 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004931 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4932 hdev->devid_product = __le16_to_cpu(cp->product);
4933 hdev->devid_version = __le16_to_cpu(cp->version);
4934
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004935 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4936 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004937
Johan Hedberg890ea892013-03-15 17:06:52 -05004938 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004939 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004940 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004941
4942 hci_dev_unlock(hdev);
4943
4944 return err;
4945}
4946
Arman Uguray24b4f382015-03-23 15:57:12 -07004947static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4948 u16 opcode)
4949{
Marcel Holtmann181d6952020-05-06 09:57:47 +02004950 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07004951}
4952
Marcel Holtmann1904a852015-01-11 13:50:44 -08004953static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4954 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004955{
4956 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004957 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004958 u8 instance;
4959 struct adv_info *adv_instance;
4960 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004961
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304962 hci_dev_lock(hdev);
4963
Johan Hedberg4375f102013-09-25 13:26:10 +03004964 if (status) {
4965 u8 mgmt_err = mgmt_status(status);
4966
4967 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4968 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304969 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004970 }
4971
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004972 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004973 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004974 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004975 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004976
Johan Hedberg4375f102013-09-25 13:26:10 +03004977 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4978 &match);
4979
4980 new_settings(hdev, match.sk);
4981
4982 if (match.sk)
4983 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304984
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004985 /* Handle suspend notifier */
4986 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
4987 hdev->suspend_tasks)) {
4988 bt_dev_dbg(hdev, "Paused advertising");
4989 wake_up(&hdev->suspend_wait_q);
4990 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
4991 hdev->suspend_tasks)) {
4992 bt_dev_dbg(hdev, "Unpaused advertising");
4993 wake_up(&hdev->suspend_wait_q);
4994 }
4995
Arman Uguray24b4f382015-03-23 15:57:12 -07004996 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004997 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004998 */
4999 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02005000 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07005001 goto unlock;
5002
Florian Grandel7816b822015-06-18 03:16:45 +02005003 instance = hdev->cur_adv_instance;
5004 if (!instance) {
5005 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
5006 struct adv_info, list);
5007 if (!adv_instance)
5008 goto unlock;
5009
5010 instance = adv_instance->instance;
5011 }
5012
Arman Uguray24b4f382015-03-23 15:57:12 -07005013 hci_req_init(&req, hdev);
5014
Johan Hedbergf2252572015-11-18 12:49:20 +02005015 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07005016
Florian Grandel7816b822015-06-18 03:16:45 +02005017 if (!err)
5018 err = hci_req_run(&req, enable_advertising_instance);
5019
5020 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005021 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07005022
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05305023unlock:
5024 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03005025}
5026
Marcel Holtmann21b51872013-10-10 09:47:53 -07005027static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5028 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03005029{
5030 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005031 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03005032 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005033 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03005034 int err;
5035
Marcel Holtmann181d6952020-05-06 09:57:47 +02005036 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03005037
Johan Hedberge6fe7982013-10-02 15:45:22 +03005038 status = mgmt_le_support(hdev);
5039 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02005040 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5041 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03005042
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005043 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005044 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03005046
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07005047 if (hdev->advertising_paused)
5048 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5049 MGMT_STATUS_BUSY);
5050
Johan Hedberg4375f102013-09-25 13:26:10 +03005051 hci_dev_lock(hdev);
5052
5053 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03005054
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02005055 /* The following conditions are ones which mean that we should
5056 * not do any HCI communication but directly send a mgmt
5057 * response to user space (after toggling the flag if
5058 * necessary).
5059 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005060 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005061 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
5062 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005063 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005064 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03005065 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005066 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03005067
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005068 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02005069 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07005070 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005071 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005072 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005073 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005074 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005075 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005076 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005077 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03005078 }
5079
5080 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
5081 if (err < 0)
5082 goto unlock;
5083
5084 if (changed)
5085 err = new_settings(hdev, sk);
5086
5087 goto unlock;
5088 }
5089
Johan Hedberg333ae952015-03-17 13:48:47 +02005090 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
5091 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005092 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
5093 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03005094 goto unlock;
5095 }
5096
5097 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
5098 if (!cmd) {
5099 err = -ENOMEM;
5100 goto unlock;
5101 }
5102
5103 hci_req_init(&req, hdev);
5104
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005105 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005106 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005107 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005108 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07005109
Florian Grandel7816b822015-06-18 03:16:45 +02005110 cancel_adv_timeout(hdev);
5111
Arman Uguray24b4f382015-03-23 15:57:12 -07005112 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02005113 /* Switch to instance "0" for the Set Advertising setting.
5114 * We cannot use update_[adv|scan_rsp]_data() here as the
5115 * HCI_ADVERTISING flag is not yet set.
5116 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005117 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05305118
5119 if (ext_adv_capable(hdev)) {
5120 __hci_req_start_ext_adv(&req, 0x00);
5121 } else {
5122 __hci_req_update_adv_data(&req, 0x00);
5123 __hci_req_update_scan_rsp_data(&req, 0x00);
5124 __hci_req_enable_advertising(&req);
5125 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005126 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02005127 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07005128 }
Johan Hedberg4375f102013-09-25 13:26:10 +03005129
5130 err = hci_req_run(&req, set_advertising_complete);
5131 if (err < 0)
5132 mgmt_pending_remove(cmd);
5133
5134unlock:
5135 hci_dev_unlock(hdev);
5136 return err;
5137}
5138
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005139static int set_static_address(struct sock *sk, struct hci_dev *hdev,
5140 void *data, u16 len)
5141{
5142 struct mgmt_cp_set_static_address *cp = data;
5143 int err;
5144
Marcel Holtmann181d6952020-05-06 09:57:47 +02005145 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005146
Marcel Holtmann62af4442013-10-02 22:10:32 -07005147 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005148 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5149 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005150
5151 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005152 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
5153 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005154
5155 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
5156 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02005157 return mgmt_cmd_status(sk, hdev->id,
5158 MGMT_OP_SET_STATIC_ADDRESS,
5159 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005160
5161 /* Two most significant bits shall be set */
5162 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02005163 return mgmt_cmd_status(sk, hdev->id,
5164 MGMT_OP_SET_STATIC_ADDRESS,
5165 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005166 }
5167
5168 hci_dev_lock(hdev);
5169
5170 bacpy(&hdev->static_addr, &cp->bdaddr);
5171
Marcel Holtmann93690c22015-03-06 10:11:21 -08005172 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
5173 if (err < 0)
5174 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005175
Marcel Holtmann93690c22015-03-06 10:11:21 -08005176 err = new_settings(hdev, sk);
5177
5178unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005179 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07005180 return err;
5181}
5182
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005183static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
5184 void *data, u16 len)
5185{
5186 struct mgmt_cp_set_scan_params *cp = data;
5187 __u16 interval, window;
5188 int err;
5189
Marcel Holtmann181d6952020-05-06 09:57:47 +02005190 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005191
5192 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005193 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5194 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005195
5196 interval = __le16_to_cpu(cp->interval);
5197
5198 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005199 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5200 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005201
5202 window = __le16_to_cpu(cp->window);
5203
5204 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02005205 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5206 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005207
Marcel Holtmann899e1072013-10-14 09:55:32 -07005208 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02005209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
5210 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07005211
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005212 hci_dev_lock(hdev);
5213
5214 hdev->le_scan_interval = interval;
5215 hdev->le_scan_window = window;
5216
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005217 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
5218 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005219
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005220 /* If background scan is running, restart it so new parameters are
5221 * loaded.
5222 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005223 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03005224 hdev->discovery.state == DISCOVERY_STOPPED) {
5225 struct hci_request req;
5226
5227 hci_req_init(&req, hdev);
5228
5229 hci_req_add_le_scan_disable(&req);
5230 hci_req_add_le_passive_scan(&req);
5231
5232 hci_req_run(&req, NULL);
5233 }
5234
Marcel Holtmann14b49b92013-10-11 08:23:20 -07005235 hci_dev_unlock(hdev);
5236
5237 return err;
5238}
5239
Marcel Holtmann1904a852015-01-11 13:50:44 -08005240static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
5241 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05005242{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005243 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005244
Marcel Holtmann181d6952020-05-06 09:57:47 +02005245 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005246
5247 hci_dev_lock(hdev);
5248
Johan Hedberg333ae952015-03-17 13:48:47 +02005249 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005250 if (!cmd)
5251 goto unlock;
5252
5253 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005254 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5255 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05005256 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005257 struct mgmt_mode *cp = cmd->param;
5258
5259 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005260 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005261 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005262 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005263
Johan Hedberg33e38b32013-03-15 17:07:05 -05005264 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
5265 new_settings(hdev, cmd->sk);
5266 }
5267
5268 mgmt_pending_remove(cmd);
5269
5270unlock:
5271 hci_dev_unlock(hdev);
5272}
5273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005274static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005275 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03005276{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03005277 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005278 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05005279 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03005280 int err;
5281
Marcel Holtmann181d6952020-05-06 09:57:47 +02005282 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005283
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005284 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03005285 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02005286 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5287 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03005288
Johan Hedberga7e80f22013-01-09 16:05:19 +02005289 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005290 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02005292
Antti Julkuf6422ec2011-06-22 13:11:56 +03005293 hci_dev_lock(hdev);
5294
Johan Hedberg333ae952015-03-17 13:48:47 +02005295 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005296 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5297 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05005298 goto unlock;
5299 }
5300
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005301 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05005302 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5303 hdev);
5304 goto unlock;
5305 }
5306
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005307 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07005308 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02005309 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
5310 hdev);
5311 new_settings(hdev, sk);
5312 goto unlock;
5313 }
5314
Johan Hedberg33e38b32013-03-15 17:07:05 -05005315 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
5316 data, len);
5317 if (!cmd) {
5318 err = -ENOMEM;
5319 goto unlock;
5320 }
5321
5322 hci_req_init(&req, hdev);
5323
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005324 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005325
5326 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005327 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005328 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
5329 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005330 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03005331 }
5332
Johan Hedberg33e38b32013-03-15 17:07:05 -05005333unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03005334 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05005335
Antti Julkuf6422ec2011-06-22 13:11:56 +03005336 return err;
5337}
5338
Marcel Holtmann1904a852015-01-11 13:50:44 -08005339static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005340{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005341 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005342
Marcel Holtmann181d6952020-05-06 09:57:47 +02005343 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005344
5345 hci_dev_lock(hdev);
5346
Johan Hedberg333ae952015-03-17 13:48:47 +02005347 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005348 if (!cmd)
5349 goto unlock;
5350
5351 if (status) {
5352 u8 mgmt_err = mgmt_status(status);
5353
5354 /* We need to restore the flag if related HCI commands
5355 * failed.
5356 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005357 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005358
Johan Hedberga69e8372015-03-06 21:08:53 +02005359 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005360 } else {
5361 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5362 new_settings(hdev, cmd->sk);
5363 }
5364
5365 mgmt_pending_remove(cmd);
5366
5367unlock:
5368 hci_dev_unlock(hdev);
5369}
5370
5371static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5372{
5373 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005374 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005375 struct hci_request req;
5376 int err;
5377
Marcel Holtmann181d6952020-05-06 09:57:47 +02005378 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005379
5380 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005381 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5382 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005383
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005384 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005385 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5386 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005387
5388 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005389 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005391
5392 hci_dev_lock(hdev);
5393
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005394 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005395 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5396 goto unlock;
5397 }
5398
5399 if (!hdev_is_powered(hdev)) {
5400 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005401 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5402 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5403 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5404 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5405 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005406 }
5407
Marcel Holtmannce05d602015-03-13 02:11:03 -07005408 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005409
5410 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5411 if (err < 0)
5412 goto unlock;
5413
5414 err = new_settings(hdev, sk);
5415 goto unlock;
5416 }
5417
5418 /* Reject disabling when powered on */
5419 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005420 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5421 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005422 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005423 } else {
5424 /* When configuring a dual-mode controller to operate
5425 * with LE only and using a static address, then switching
5426 * BR/EDR back on is not allowed.
5427 *
5428 * Dual-mode controllers shall operate with the public
5429 * address as its identity address for BR/EDR and LE. So
5430 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005431 *
5432 * The same restrictions applies when secure connections
5433 * has been enabled. For BR/EDR this is a controller feature
5434 * while for LE it is a host stack feature. This means that
5435 * switching BR/EDR back on when secure connections has been
5436 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005437 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005438 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005439 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005440 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005441 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5442 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005443 goto unlock;
5444 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005445 }
5446
Johan Hedberg333ae952015-03-17 13:48:47 +02005447 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005448 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5449 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005450 goto unlock;
5451 }
5452
5453 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5454 if (!cmd) {
5455 err = -ENOMEM;
5456 goto unlock;
5457 }
5458
Johan Hedbergf2252572015-11-18 12:49:20 +02005459 /* We need to flip the bit already here so that
5460 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005461 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005462 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005463
5464 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005465
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005466 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005467 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005468
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005469 /* Since only the advertising data flags will change, there
5470 * is no need to update the scan response data.
5471 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005472 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005473
Johan Hedberg0663ca22013-10-02 13:43:14 +03005474 err = hci_req_run(&req, set_bredr_complete);
5475 if (err < 0)
5476 mgmt_pending_remove(cmd);
5477
5478unlock:
5479 hci_dev_unlock(hdev);
5480 return err;
5481}
5482
Johan Hedberga1443f52015-01-23 15:42:46 +02005483static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5484{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005485 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005486 struct mgmt_mode *cp;
5487
Marcel Holtmann181d6952020-05-06 09:57:47 +02005488 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005489
5490 hci_dev_lock(hdev);
5491
Johan Hedberg333ae952015-03-17 13:48:47 +02005492 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005493 if (!cmd)
5494 goto unlock;
5495
5496 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005497 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5498 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005499 goto remove;
5500 }
5501
5502 cp = cmd->param;
5503
5504 switch (cp->val) {
5505 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005506 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5507 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005508 break;
5509 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005510 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005511 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005512 break;
5513 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005514 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5515 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005516 break;
5517 }
5518
5519 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5520 new_settings(hdev, cmd->sk);
5521
5522remove:
5523 mgmt_pending_remove(cmd);
5524unlock:
5525 hci_dev_unlock(hdev);
5526}
5527
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005528static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5529 void *data, u16 len)
5530{
5531 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005532 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005533 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005534 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005535 int err;
5536
Marcel Holtmann181d6952020-05-06 09:57:47 +02005537 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005538
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005539 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005540 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005541 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5542 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005543
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005544 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005545 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005546 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005547 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5548 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005549
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005550 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005551 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005552 MGMT_STATUS_INVALID_PARAMS);
5553
5554 hci_dev_lock(hdev);
5555
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005556 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005557 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005558 bool changed;
5559
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005560 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005561 changed = !hci_dev_test_and_set_flag(hdev,
5562 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005563 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005564 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005565 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005566 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005567 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005568 changed = hci_dev_test_and_clear_flag(hdev,
5569 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005570 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005571 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005572
5573 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5574 if (err < 0)
5575 goto failed;
5576
5577 if (changed)
5578 err = new_settings(hdev, sk);
5579
5580 goto failed;
5581 }
5582
Johan Hedberg333ae952015-03-17 13:48:47 +02005583 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005584 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5585 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005586 goto failed;
5587 }
5588
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005589 val = !!cp->val;
5590
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005591 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5592 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005593 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5594 goto failed;
5595 }
5596
5597 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5598 if (!cmd) {
5599 err = -ENOMEM;
5600 goto failed;
5601 }
5602
Johan Hedberga1443f52015-01-23 15:42:46 +02005603 hci_req_init(&req, hdev);
5604 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5605 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005606 if (err < 0) {
5607 mgmt_pending_remove(cmd);
5608 goto failed;
5609 }
5610
5611failed:
5612 hci_dev_unlock(hdev);
5613 return err;
5614}
5615
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005616static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5617 void *data, u16 len)
5618{
5619 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005620 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005621 int err;
5622
Marcel Holtmann181d6952020-05-06 09:57:47 +02005623 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005624
Johan Hedbergb97109792014-06-24 14:00:28 +03005625 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5627 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005628
5629 hci_dev_lock(hdev);
5630
5631 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005632 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005633 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005634 changed = hci_dev_test_and_clear_flag(hdev,
5635 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005636
Johan Hedbergb97109792014-06-24 14:00:28 +03005637 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005638 use_changed = !hci_dev_test_and_set_flag(hdev,
5639 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005640 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005641 use_changed = hci_dev_test_and_clear_flag(hdev,
5642 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005643
5644 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005645 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005646 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5647 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5648 sizeof(mode), &mode);
5649 }
5650
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005651 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5652 if (err < 0)
5653 goto unlock;
5654
5655 if (changed)
5656 err = new_settings(hdev, sk);
5657
5658unlock:
5659 hci_dev_unlock(hdev);
5660 return err;
5661}
5662
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005663static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5664 u16 len)
5665{
5666 struct mgmt_cp_set_privacy *cp = cp_data;
5667 bool changed;
5668 int err;
5669
Marcel Holtmann181d6952020-05-06 09:57:47 +02005670 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005671
5672 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005673 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5674 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005675
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005676 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5678 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005679
5680 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005681 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5682 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005683
5684 hci_dev_lock(hdev);
5685
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005686 /* If user space supports this command it is also expected to
5687 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5688 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005689 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005690
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005691 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005692 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005693 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005694 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305695 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005696 if (cp->privacy == 0x02)
5697 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5698 else
5699 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005700 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005701 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005702 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005703 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305704 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005705 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005706 }
5707
5708 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5709 if (err < 0)
5710 goto unlock;
5711
5712 if (changed)
5713 err = new_settings(hdev, sk);
5714
5715unlock:
5716 hci_dev_unlock(hdev);
5717 return err;
5718}
5719
Johan Hedberg41edf162014-02-18 10:19:35 +02005720static bool irk_is_valid(struct mgmt_irk_info *irk)
5721{
5722 switch (irk->addr.type) {
5723 case BDADDR_LE_PUBLIC:
5724 return true;
5725
5726 case BDADDR_LE_RANDOM:
5727 /* Two most significant bits shall be set */
5728 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5729 return false;
5730 return true;
5731 }
5732
5733 return false;
5734}
5735
5736static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5737 u16 len)
5738{
5739 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005740 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5741 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005742 u16 irk_count, expected_len;
5743 int i, err;
5744
Marcel Holtmann181d6952020-05-06 09:57:47 +02005745 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005746
5747 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5749 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005750
5751 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005752 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005753 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5754 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005755 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005757 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005758
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005759 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005760 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005761 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5762 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005763 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5764 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005765 }
5766
Marcel Holtmann181d6952020-05-06 09:57:47 +02005767 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005768
5769 for (i = 0; i < irk_count; i++) {
5770 struct mgmt_irk_info *key = &cp->irks[i];
5771
5772 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005773 return mgmt_cmd_status(sk, hdev->id,
5774 MGMT_OP_LOAD_IRKS,
5775 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005776 }
5777
5778 hci_dev_lock(hdev);
5779
5780 hci_smp_irks_clear(hdev);
5781
5782 for (i = 0; i < irk_count; i++) {
5783 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005784
Alain Michaud600a8742020-01-07 00:43:17 +00005785 if (hci_is_blocked_key(hdev,
5786 HCI_BLOCKED_KEY_TYPE_IRK,
5787 irk->val)) {
5788 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5789 &irk->addr.bdaddr);
5790 continue;
5791 }
5792
Johan Hedberg85813a72015-10-21 18:02:59 +03005793 hci_add_irk(hdev, &irk->addr.bdaddr,
5794 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005795 BDADDR_ANY);
5796 }
5797
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005798 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005799
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005800 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005801
5802 hci_dev_unlock(hdev);
5803
5804 return err;
5805}
5806
Johan Hedberg3f706b72013-01-20 14:27:16 +02005807static bool ltk_is_valid(struct mgmt_ltk_info *key)
5808{
5809 if (key->master != 0x00 && key->master != 0x01)
5810 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005811
5812 switch (key->addr.type) {
5813 case BDADDR_LE_PUBLIC:
5814 return true;
5815
5816 case BDADDR_LE_RANDOM:
5817 /* Two most significant bits shall be set */
5818 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5819 return false;
5820 return true;
5821 }
5822
5823 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005824}
5825
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005826static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005827 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005828{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005829 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005830 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5831 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005832 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005833 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005834
Marcel Holtmann181d6952020-05-06 09:57:47 +02005835 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005836
5837 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005838 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5839 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005840
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005841 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005842 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005843 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5844 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005845 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5846 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005847 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005848
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005849 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005850 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005851 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5852 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005853 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5854 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005855 }
5856
Marcel Holtmann181d6952020-05-06 09:57:47 +02005857 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005858
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005859 for (i = 0; i < key_count; i++) {
5860 struct mgmt_ltk_info *key = &cp->keys[i];
5861
Johan Hedberg3f706b72013-01-20 14:27:16 +02005862 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005863 return mgmt_cmd_status(sk, hdev->id,
5864 MGMT_OP_LOAD_LONG_TERM_KEYS,
5865 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005866 }
5867
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005868 hci_dev_lock(hdev);
5869
5870 hci_smp_ltks_clear(hdev);
5871
5872 for (i = 0; i < key_count; i++) {
5873 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005874 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005875
Alain Michaud600a8742020-01-07 00:43:17 +00005876 if (hci_is_blocked_key(hdev,
5877 HCI_BLOCKED_KEY_TYPE_LTK,
5878 key->val)) {
5879 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5880 &key->addr.bdaddr);
5881 continue;
5882 }
5883
Johan Hedberg61b43352014-05-29 19:36:53 +03005884 switch (key->type) {
5885 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005886 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005887 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005888 break;
5889 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005890 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005891 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005892 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005893 case MGMT_LTK_P256_UNAUTH:
5894 authenticated = 0x00;
5895 type = SMP_LTK_P256;
5896 break;
5897 case MGMT_LTK_P256_AUTH:
5898 authenticated = 0x01;
5899 type = SMP_LTK_P256;
5900 break;
5901 case MGMT_LTK_P256_DEBUG:
5902 authenticated = 0x00;
5903 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005904 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005905 default:
5906 continue;
5907 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005908
Johan Hedberg85813a72015-10-21 18:02:59 +03005909 hci_add_ltk(hdev, &key->addr.bdaddr,
5910 le_addr_type(key->addr.type), type, authenticated,
5911 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005912 }
5913
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005914 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005915 NULL, 0);
5916
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005917 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005918
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005919 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005920}
5921
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005922static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005923{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005924 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005925 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005926 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005927
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005928 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005929
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005930 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005931 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005932 rp.tx_power = conn->tx_power;
5933 rp.max_tx_power = conn->max_tx_power;
5934 } else {
5935 rp.rssi = HCI_RSSI_INVALID;
5936 rp.tx_power = HCI_TX_POWER_INVALID;
5937 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005938 }
5939
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005940 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5941 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005942
5943 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005944 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005945
5946 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005947}
5948
Marcel Holtmann1904a852015-01-11 13:50:44 -08005949static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5950 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005951{
5952 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005953 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005954 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005955 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005956 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005957
Marcel Holtmann181d6952020-05-06 09:57:47 +02005958 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005959
5960 hci_dev_lock(hdev);
5961
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005962 /* Commands sent in request are either Read RSSI or Read Transmit Power
5963 * Level so we check which one was last sent to retrieve connection
5964 * handle. Both commands have handle as first parameter so it's safe to
5965 * cast data on the same command struct.
5966 *
5967 * First command sent is always Read RSSI and we fail only if it fails.
5968 * In other case we simply override error to indicate success as we
5969 * already remembered if TX power value is actually valid.
5970 */
5971 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5972 if (!cp) {
5973 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005974 status = MGMT_STATUS_SUCCESS;
5975 } else {
5976 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005977 }
5978
5979 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005980 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005981 goto unlock;
5982 }
5983
5984 handle = __le16_to_cpu(cp->handle);
5985 conn = hci_conn_hash_lookup_handle(hdev, handle);
5986 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005987 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5988 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005989 goto unlock;
5990 }
5991
Johan Hedberg333ae952015-03-17 13:48:47 +02005992 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005993 if (!cmd)
5994 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005995
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005996 cmd->cmd_complete(cmd, status);
5997 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005998
5999unlock:
6000 hci_dev_unlock(hdev);
6001}
6002
6003static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
6004 u16 len)
6005{
6006 struct mgmt_cp_get_conn_info *cp = data;
6007 struct mgmt_rp_get_conn_info rp;
6008 struct hci_conn *conn;
6009 unsigned long conn_info_age;
6010 int err = 0;
6011
Marcel Holtmann181d6952020-05-06 09:57:47 +02006012 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006013
6014 memset(&rp, 0, sizeof(rp));
6015 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6016 rp.addr.type = cp->addr.type;
6017
6018 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006019 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6020 MGMT_STATUS_INVALID_PARAMS,
6021 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006022
6023 hci_dev_lock(hdev);
6024
6025 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006026 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6027 MGMT_STATUS_NOT_POWERED, &rp,
6028 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006029 goto unlock;
6030 }
6031
6032 if (cp->addr.type == BDADDR_BREDR)
6033 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6034 &cp->addr.bdaddr);
6035 else
6036 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
6037
6038 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006039 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6040 MGMT_STATUS_NOT_CONNECTED, &rp,
6041 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006042 goto unlock;
6043 }
6044
Johan Hedberg333ae952015-03-17 13:48:47 +02006045 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006046 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6047 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006048 goto unlock;
6049 }
6050
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006051 /* To avoid client trying to guess when to poll again for information we
6052 * calculate conn info age as random value between min/max set in hdev.
6053 */
6054 conn_info_age = hdev->conn_info_min_age +
6055 prandom_u32_max(hdev->conn_info_max_age -
6056 hdev->conn_info_min_age);
6057
6058 /* Query controller to refresh cached values if they are too old or were
6059 * never read.
6060 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02006061 if (time_after(jiffies, conn->conn_info_timestamp +
6062 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006063 !conn->conn_info_timestamp) {
6064 struct hci_request req;
6065 struct hci_cp_read_tx_power req_txp_cp;
6066 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006067 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006068
6069 hci_req_init(&req, hdev);
6070 req_rssi_cp.handle = cpu_to_le16(conn->handle);
6071 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
6072 &req_rssi_cp);
6073
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02006074 /* For LE links TX power does not change thus we don't need to
6075 * query for it once value is known.
6076 */
6077 if (!bdaddr_type_is_le(cp->addr.type) ||
6078 conn->tx_power == HCI_TX_POWER_INVALID) {
6079 req_txp_cp.handle = cpu_to_le16(conn->handle);
6080 req_txp_cp.type = 0x00;
6081 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6082 sizeof(req_txp_cp), &req_txp_cp);
6083 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006084
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006085 /* Max TX power needs to be read only once per connection */
6086 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
6087 req_txp_cp.handle = cpu_to_le16(conn->handle);
6088 req_txp_cp.type = 0x01;
6089 hci_req_add(&req, HCI_OP_READ_TX_POWER,
6090 sizeof(req_txp_cp), &req_txp_cp);
6091 }
6092
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006093 err = hci_req_run(&req, conn_info_refresh_complete);
6094 if (err < 0)
6095 goto unlock;
6096
6097 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
6098 data, len);
6099 if (!cmd) {
6100 err = -ENOMEM;
6101 goto unlock;
6102 }
6103
6104 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006105 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02006106 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006107
6108 conn->conn_info_timestamp = jiffies;
6109 } else {
6110 /* Cache is valid, just reply with values cached in hci_conn */
6111 rp.rssi = conn->rssi;
6112 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02006113 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006114
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006115 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
6116 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02006117 }
6118
6119unlock:
6120 hci_dev_unlock(hdev);
6121 return err;
6122}
6123
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006124static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02006125{
6126 struct hci_conn *conn = cmd->user_data;
6127 struct mgmt_rp_get_clock_info rp;
6128 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02006129 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02006130
6131 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02006132 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02006133
6134 if (status)
6135 goto complete;
6136
6137 hdev = hci_dev_get(cmd->index);
6138 if (hdev) {
6139 rp.local_clock = cpu_to_le32(hdev->clock);
6140 hci_dev_put(hdev);
6141 }
6142
6143 if (conn) {
6144 rp.piconet_clock = cpu_to_le32(conn->clock);
6145 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
6146 }
6147
6148complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006149 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
6150 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02006151
6152 if (conn) {
6153 hci_conn_drop(conn);
6154 hci_conn_put(conn);
6155 }
Johan Hedberg9df74652014-12-19 22:26:03 +02006156
6157 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02006158}
6159
Marcel Holtmann1904a852015-01-11 13:50:44 -08006160static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03006161{
Johan Hedberg95868422014-06-28 17:54:07 +03006162 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006163 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006164 struct hci_conn *conn;
6165
Marcel Holtmann181d6952020-05-06 09:57:47 +02006166 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03006167
6168 hci_dev_lock(hdev);
6169
6170 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
6171 if (!hci_cp)
6172 goto unlock;
6173
6174 if (hci_cp->which) {
6175 u16 handle = __le16_to_cpu(hci_cp->handle);
6176 conn = hci_conn_hash_lookup_handle(hdev, handle);
6177 } else {
6178 conn = NULL;
6179 }
6180
Johan Hedberg333ae952015-03-17 13:48:47 +02006181 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006182 if (!cmd)
6183 goto unlock;
6184
Johan Hedberg69487372014-12-05 13:36:07 +02006185 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03006186 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03006187
6188unlock:
6189 hci_dev_unlock(hdev);
6190}
6191
6192static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
6193 u16 len)
6194{
6195 struct mgmt_cp_get_clock_info *cp = data;
6196 struct mgmt_rp_get_clock_info rp;
6197 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006198 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03006199 struct hci_request req;
6200 struct hci_conn *conn;
6201 int err;
6202
Marcel Holtmann181d6952020-05-06 09:57:47 +02006203 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03006204
6205 memset(&rp, 0, sizeof(rp));
6206 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
6207 rp.addr.type = cp->addr.type;
6208
6209 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006210 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6211 MGMT_STATUS_INVALID_PARAMS,
6212 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006213
6214 hci_dev_lock(hdev);
6215
6216 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006217 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
6218 MGMT_STATUS_NOT_POWERED, &rp,
6219 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006220 goto unlock;
6221 }
6222
6223 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
6224 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
6225 &cp->addr.bdaddr);
6226 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006227 err = mgmt_cmd_complete(sk, hdev->id,
6228 MGMT_OP_GET_CLOCK_INFO,
6229 MGMT_STATUS_NOT_CONNECTED,
6230 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03006231 goto unlock;
6232 }
6233 } else {
6234 conn = NULL;
6235 }
6236
6237 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
6238 if (!cmd) {
6239 err = -ENOMEM;
6240 goto unlock;
6241 }
6242
Johan Hedberg69487372014-12-05 13:36:07 +02006243 cmd->cmd_complete = clock_info_cmd_complete;
6244
Johan Hedberg95868422014-06-28 17:54:07 +03006245 hci_req_init(&req, hdev);
6246
6247 memset(&hci_cp, 0, sizeof(hci_cp));
6248 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6249
6250 if (conn) {
6251 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03006252 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03006253
6254 hci_cp.handle = cpu_to_le16(conn->handle);
6255 hci_cp.which = 0x01; /* Piconet clock */
6256 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
6257 }
6258
6259 err = hci_req_run(&req, get_clock_info_complete);
6260 if (err < 0)
6261 mgmt_pending_remove(cmd);
6262
6263unlock:
6264 hci_dev_unlock(hdev);
6265 return err;
6266}
6267
Johan Hedberg5a154e62014-12-19 22:26:02 +02006268static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
6269{
6270 struct hci_conn *conn;
6271
6272 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
6273 if (!conn)
6274 return false;
6275
6276 if (conn->dst_type != type)
6277 return false;
6278
6279 if (conn->state != BT_CONNECTED)
6280 return false;
6281
6282 return true;
6283}
6284
6285/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006286static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02006287 u8 addr_type, u8 auto_connect)
6288{
Johan Hedberg5a154e62014-12-19 22:26:02 +02006289 struct hci_conn_params *params;
6290
6291 params = hci_conn_params_add(hdev, addr, addr_type);
6292 if (!params)
6293 return -EIO;
6294
6295 if (params->auto_connect == auto_connect)
6296 return 0;
6297
6298 list_del_init(&params->action);
6299
6300 switch (auto_connect) {
6301 case HCI_AUTO_CONN_DISABLED:
6302 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02006303 /* If auto connect is being disabled when we're trying to
6304 * connect to device, keep connecting.
6305 */
6306 if (params->explicit_connect)
6307 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006308 break;
6309 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03006310 if (params->explicit_connect)
6311 list_add(&params->action, &hdev->pend_le_conns);
6312 else
6313 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006314 break;
6315 case HCI_AUTO_CONN_DIRECT:
6316 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006317 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02006318 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006319 break;
6320 }
6321
6322 params->auto_connect = auto_connect;
6323
Marcel Holtmann181d6952020-05-06 09:57:47 +02006324 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
6325 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006326
6327 return 0;
6328}
6329
Marcel Holtmann8afef092014-06-29 22:28:34 +02006330static void device_added(struct sock *sk, struct hci_dev *hdev,
6331 bdaddr_t *bdaddr, u8 type, u8 action)
6332{
6333 struct mgmt_ev_device_added ev;
6334
6335 bacpy(&ev.addr.bdaddr, bdaddr);
6336 ev.addr.type = type;
6337 ev.action = action;
6338
6339 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
6340}
6341
Marcel Holtmann2faade52014-06-29 19:44:03 +02006342static int add_device(struct sock *sk, struct hci_dev *hdev,
6343 void *data, u16 len)
6344{
6345 struct mgmt_cp_add_device *cp = data;
6346 u8 auto_conn, addr_type;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006347 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006348 int err;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006349 u32 current_flags = 0;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006350
Marcel Holtmann181d6952020-05-06 09:57:47 +02006351 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006352
Johan Hedberg66593582014-07-09 12:59:14 +03006353 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006354 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006355 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6356 MGMT_STATUS_INVALID_PARAMS,
6357 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006358
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006359 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006360 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6361 MGMT_STATUS_INVALID_PARAMS,
6362 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006363
6364 hci_dev_lock(hdev);
6365
Johan Hedberg66593582014-07-09 12:59:14 +03006366 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006367 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006368 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006369 err = mgmt_cmd_complete(sk, hdev->id,
6370 MGMT_OP_ADD_DEVICE,
6371 MGMT_STATUS_INVALID_PARAMS,
6372 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006373 goto unlock;
6374 }
6375
Abhishek Pandit-Subedi8baaa402020-06-17 16:39:08 +02006376 err = hci_bdaddr_list_add_with_flags(&hdev->whitelist,
6377 &cp->addr.bdaddr,
6378 cp->addr.type, 0);
Johan Hedberg66593582014-07-09 12:59:14 +03006379 if (err)
6380 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006381
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006382 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006383
Johan Hedberg66593582014-07-09 12:59:14 +03006384 goto added;
6385 }
6386
Johan Hedberg85813a72015-10-21 18:02:59 +03006387 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006388
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006389 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006390 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006391 else if (cp->action == 0x01)
6392 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006393 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006394 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006395
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006396 /* Kernel internally uses conn_params with resolvable private
6397 * address, but Add Device allows only identity addresses.
6398 * Make sure it is enforced before calling
6399 * hci_conn_params_lookup.
6400 */
6401 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006402 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6403 MGMT_STATUS_INVALID_PARAMS,
6404 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006405 goto unlock;
6406 }
6407
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006408 /* If the connection parameters don't exist for this device,
6409 * they will be created and configured with defaults.
6410 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006411 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006412 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006413 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6414 MGMT_STATUS_FAILED, &cp->addr,
6415 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006416 goto unlock;
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006417 } else {
6418 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6419 addr_type);
6420 if (params)
6421 current_flags = params->current_flags;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006422 }
6423
Johan Hedberg51d7a942015-11-11 08:11:18 +02006424 hci_update_background_scan(hdev);
6425
Johan Hedberg66593582014-07-09 12:59:14 +03006426added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006427 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02006428 device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
6429 SUPPORTED_DEVICE_FLAGS(), current_flags);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006430
Johan Hedberg51d7a942015-11-11 08:11:18 +02006431 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6432 MGMT_STATUS_SUCCESS, &cp->addr,
6433 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006434
6435unlock:
6436 hci_dev_unlock(hdev);
6437 return err;
6438}
6439
Marcel Holtmann8afef092014-06-29 22:28:34 +02006440static void device_removed(struct sock *sk, struct hci_dev *hdev,
6441 bdaddr_t *bdaddr, u8 type)
6442{
6443 struct mgmt_ev_device_removed ev;
6444
6445 bacpy(&ev.addr.bdaddr, bdaddr);
6446 ev.addr.type = type;
6447
6448 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6449}
6450
Marcel Holtmann2faade52014-06-29 19:44:03 +02006451static int remove_device(struct sock *sk, struct hci_dev *hdev,
6452 void *data, u16 len)
6453{
6454 struct mgmt_cp_remove_device *cp = data;
6455 int err;
6456
Marcel Holtmann181d6952020-05-06 09:57:47 +02006457 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006458
6459 hci_dev_lock(hdev);
6460
6461 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006462 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006463 u8 addr_type;
6464
Johan Hedberg66593582014-07-09 12:59:14 +03006465 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006466 err = mgmt_cmd_complete(sk, hdev->id,
6467 MGMT_OP_REMOVE_DEVICE,
6468 MGMT_STATUS_INVALID_PARAMS,
6469 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006470 goto unlock;
6471 }
6472
Johan Hedberg66593582014-07-09 12:59:14 +03006473 if (cp->addr.type == BDADDR_BREDR) {
6474 err = hci_bdaddr_list_del(&hdev->whitelist,
6475 &cp->addr.bdaddr,
6476 cp->addr.type);
6477 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006478 err = mgmt_cmd_complete(sk, hdev->id,
6479 MGMT_OP_REMOVE_DEVICE,
6480 MGMT_STATUS_INVALID_PARAMS,
6481 &cp->addr,
6482 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006483 goto unlock;
6484 }
6485
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006486 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006487
Johan Hedberg66593582014-07-09 12:59:14 +03006488 device_removed(sk, hdev, &cp->addr.bdaddr,
6489 cp->addr.type);
6490 goto complete;
6491 }
6492
Johan Hedberg85813a72015-10-21 18:02:59 +03006493 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006494
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006495 /* Kernel internally uses conn_params with resolvable private
6496 * address, but Remove Device allows only identity addresses.
6497 * Make sure it is enforced before calling
6498 * hci_conn_params_lookup.
6499 */
6500 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006501 err = mgmt_cmd_complete(sk, hdev->id,
6502 MGMT_OP_REMOVE_DEVICE,
6503 MGMT_STATUS_INVALID_PARAMS,
6504 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006505 goto unlock;
6506 }
6507
Johan Hedbergc71593d2014-07-02 17:37:28 +03006508 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6509 addr_type);
6510 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006511 err = mgmt_cmd_complete(sk, hdev->id,
6512 MGMT_OP_REMOVE_DEVICE,
6513 MGMT_STATUS_INVALID_PARAMS,
6514 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006515 goto unlock;
6516 }
6517
Johan Hedberg679d2b62015-10-16 10:07:52 +03006518 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6519 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006520 err = mgmt_cmd_complete(sk, hdev->id,
6521 MGMT_OP_REMOVE_DEVICE,
6522 MGMT_STATUS_INVALID_PARAMS,
6523 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006524 goto unlock;
6525 }
6526
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006527 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006528 list_del(&params->list);
6529 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006530 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006531
6532 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006533 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006534 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006535 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006536
Marcel Holtmann2faade52014-06-29 19:44:03 +02006537 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006538 err = mgmt_cmd_complete(sk, hdev->id,
6539 MGMT_OP_REMOVE_DEVICE,
6540 MGMT_STATUS_INVALID_PARAMS,
6541 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006542 goto unlock;
6543 }
6544
Johan Hedberg66593582014-07-09 12:59:14 +03006545 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6546 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6547 list_del(&b->list);
6548 kfree(b);
6549 }
6550
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006551 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006552
Johan Hedberg19de0822014-07-06 13:06:51 +03006553 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6554 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6555 continue;
6556 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006557 if (p->explicit_connect) {
6558 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6559 continue;
6560 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006561 list_del(&p->action);
6562 list_del(&p->list);
6563 kfree(p);
6564 }
6565
Marcel Holtmann181d6952020-05-06 09:57:47 +02006566 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006567
Johan Hedberg51d7a942015-11-11 08:11:18 +02006568 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006569 }
6570
Johan Hedberg66593582014-07-09 12:59:14 +03006571complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006572 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6573 MGMT_STATUS_SUCCESS, &cp->addr,
6574 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006575unlock:
6576 hci_dev_unlock(hdev);
6577 return err;
6578}
6579
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006580static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6581 u16 len)
6582{
6583 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006584 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6585 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006586 u16 param_count, expected_len;
6587 int i;
6588
6589 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006590 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6591 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006592
6593 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006594 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006595 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6596 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006597 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6598 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006599 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006600
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006601 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006602 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006603 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6604 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006605 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6606 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006607 }
6608
Marcel Holtmann181d6952020-05-06 09:57:47 +02006609 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006610
6611 hci_dev_lock(hdev);
6612
6613 hci_conn_params_clear_disabled(hdev);
6614
6615 for (i = 0; i < param_count; i++) {
6616 struct mgmt_conn_param *param = &cp->params[i];
6617 struct hci_conn_params *hci_param;
6618 u16 min, max, latency, timeout;
6619 u8 addr_type;
6620
Marcel Holtmann181d6952020-05-06 09:57:47 +02006621 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6622 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006623
6624 if (param->addr.type == BDADDR_LE_PUBLIC) {
6625 addr_type = ADDR_LE_DEV_PUBLIC;
6626 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6627 addr_type = ADDR_LE_DEV_RANDOM;
6628 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006629 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006630 continue;
6631 }
6632
6633 min = le16_to_cpu(param->min_interval);
6634 max = le16_to_cpu(param->max_interval);
6635 latency = le16_to_cpu(param->latency);
6636 timeout = le16_to_cpu(param->timeout);
6637
Marcel Holtmann181d6952020-05-06 09:57:47 +02006638 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6639 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006640
6641 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006642 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006643 continue;
6644 }
6645
6646 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6647 addr_type);
6648 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006649 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006650 continue;
6651 }
6652
6653 hci_param->conn_min_interval = min;
6654 hci_param->conn_max_interval = max;
6655 hci_param->conn_latency = latency;
6656 hci_param->supervision_timeout = timeout;
6657 }
6658
6659 hci_dev_unlock(hdev);
6660
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006661 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6662 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006663}
6664
Marcel Holtmanndbece372014-07-04 18:11:55 +02006665static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6666 void *data, u16 len)
6667{
6668 struct mgmt_cp_set_external_config *cp = data;
6669 bool changed;
6670 int err;
6671
Marcel Holtmann181d6952020-05-06 09:57:47 +02006672 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006673
6674 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006675 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6676 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006677
6678 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006679 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6680 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006681
6682 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006683 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6684 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006685
6686 hci_dev_lock(hdev);
6687
6688 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006689 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006690 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006691 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006692
6693 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6694 if (err < 0)
6695 goto unlock;
6696
6697 if (!changed)
6698 goto unlock;
6699
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006700 err = new_options(hdev, sk);
6701
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006702 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006703 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006704
Marcel Holtmann516018a2015-03-13 02:11:04 -07006705 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006706 hci_dev_set_flag(hdev, HCI_CONFIG);
6707 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006708
6709 queue_work(hdev->req_workqueue, &hdev->power_on);
6710 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006711 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006712 mgmt_index_added(hdev);
6713 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006714 }
6715
6716unlock:
6717 hci_dev_unlock(hdev);
6718 return err;
6719}
6720
Marcel Holtmann9713c172014-07-06 12:11:15 +02006721static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6722 void *data, u16 len)
6723{
6724 struct mgmt_cp_set_public_address *cp = data;
6725 bool changed;
6726 int err;
6727
Marcel Holtmann181d6952020-05-06 09:57:47 +02006728 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006729
6730 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6732 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006733
6734 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006735 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6736 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006737
6738 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006739 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6740 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006741
6742 hci_dev_lock(hdev);
6743
6744 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6745 bacpy(&hdev->public_addr, &cp->bdaddr);
6746
6747 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6748 if (err < 0)
6749 goto unlock;
6750
6751 if (!changed)
6752 goto unlock;
6753
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006754 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006755 err = new_options(hdev, sk);
6756
6757 if (is_configured(hdev)) {
6758 mgmt_index_removed(hdev);
6759
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006760 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006761
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006762 hci_dev_set_flag(hdev, HCI_CONFIG);
6763 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006764
6765 queue_work(hdev->req_workqueue, &hdev->power_on);
6766 }
6767
6768unlock:
6769 hci_dev_unlock(hdev);
6770 return err;
6771}
6772
Johan Hedberg40f66c02015-04-07 21:52:22 +03006773static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6774 u16 opcode, struct sk_buff *skb)
6775{
6776 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6777 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6778 u8 *h192, *r192, *h256, *r256;
6779 struct mgmt_pending_cmd *cmd;
6780 u16 eir_len;
6781 int err;
6782
Marcel Holtmann181d6952020-05-06 09:57:47 +02006783 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006784
6785 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6786 if (!cmd)
6787 return;
6788
6789 mgmt_cp = cmd->param;
6790
6791 if (status) {
6792 status = mgmt_status(status);
6793 eir_len = 0;
6794
6795 h192 = NULL;
6796 r192 = NULL;
6797 h256 = NULL;
6798 r256 = NULL;
6799 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6800 struct hci_rp_read_local_oob_data *rp;
6801
6802 if (skb->len != sizeof(*rp)) {
6803 status = MGMT_STATUS_FAILED;
6804 eir_len = 0;
6805 } else {
6806 status = MGMT_STATUS_SUCCESS;
6807 rp = (void *)skb->data;
6808
6809 eir_len = 5 + 18 + 18;
6810 h192 = rp->hash;
6811 r192 = rp->rand;
6812 h256 = NULL;
6813 r256 = NULL;
6814 }
6815 } else {
6816 struct hci_rp_read_local_oob_ext_data *rp;
6817
6818 if (skb->len != sizeof(*rp)) {
6819 status = MGMT_STATUS_FAILED;
6820 eir_len = 0;
6821 } else {
6822 status = MGMT_STATUS_SUCCESS;
6823 rp = (void *)skb->data;
6824
6825 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6826 eir_len = 5 + 18 + 18;
6827 h192 = NULL;
6828 r192 = NULL;
6829 } else {
6830 eir_len = 5 + 18 + 18 + 18 + 18;
6831 h192 = rp->hash192;
6832 r192 = rp->rand192;
6833 }
6834
6835 h256 = rp->hash256;
6836 r256 = rp->rand256;
6837 }
6838 }
6839
6840 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6841 if (!mgmt_rp)
6842 goto done;
6843
6844 if (status)
6845 goto send_rsp;
6846
6847 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6848 hdev->dev_class, 3);
6849
6850 if (h192 && r192) {
6851 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6852 EIR_SSP_HASH_C192, h192, 16);
6853 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6854 EIR_SSP_RAND_R192, r192, 16);
6855 }
6856
6857 if (h256 && r256) {
6858 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6859 EIR_SSP_HASH_C256, h256, 16);
6860 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6861 EIR_SSP_RAND_R256, r256, 16);
6862 }
6863
6864send_rsp:
6865 mgmt_rp->type = mgmt_cp->type;
6866 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6867
6868 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6869 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6870 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6871 if (err < 0 || status)
6872 goto done;
6873
6874 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6875
6876 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6877 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6878 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6879done:
6880 kfree(mgmt_rp);
6881 mgmt_pending_remove(cmd);
6882}
6883
6884static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6885 struct mgmt_cp_read_local_oob_ext_data *cp)
6886{
6887 struct mgmt_pending_cmd *cmd;
6888 struct hci_request req;
6889 int err;
6890
6891 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6892 cp, sizeof(*cp));
6893 if (!cmd)
6894 return -ENOMEM;
6895
6896 hci_req_init(&req, hdev);
6897
6898 if (bredr_sc_enabled(hdev))
6899 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6900 else
6901 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6902
6903 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6904 if (err < 0) {
6905 mgmt_pending_remove(cmd);
6906 return err;
6907 }
6908
6909 return 0;
6910}
6911
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006912static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6913 void *data, u16 data_len)
6914{
6915 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6916 struct mgmt_rp_read_local_oob_ext_data *rp;
6917 size_t rp_len;
6918 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006919 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006920 int err;
6921
Marcel Holtmann181d6952020-05-06 09:57:47 +02006922 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006923
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006924 if (hdev_is_powered(hdev)) {
6925 switch (cp->type) {
6926 case BIT(BDADDR_BREDR):
6927 status = mgmt_bredr_support(hdev);
6928 if (status)
6929 eir_len = 0;
6930 else
6931 eir_len = 5;
6932 break;
6933 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6934 status = mgmt_le_support(hdev);
6935 if (status)
6936 eir_len = 0;
6937 else
6938 eir_len = 9 + 3 + 18 + 18 + 3;
6939 break;
6940 default:
6941 status = MGMT_STATUS_INVALID_PARAMS;
6942 eir_len = 0;
6943 break;
6944 }
6945 } else {
6946 status = MGMT_STATUS_NOT_POWERED;
6947 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006948 }
6949
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006950 rp_len = sizeof(*rp) + eir_len;
6951 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006952 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006953 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006954
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006955 if (status)
6956 goto complete;
6957
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006958 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006959
6960 eir_len = 0;
6961 switch (cp->type) {
6962 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006963 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6964 err = read_local_ssp_oob_req(hdev, sk, cp);
6965 hci_dev_unlock(hdev);
6966 if (!err)
6967 goto done;
6968
6969 status = MGMT_STATUS_FAILED;
6970 goto complete;
6971 } else {
6972 eir_len = eir_append_data(rp->eir, eir_len,
6973 EIR_CLASS_OF_DEV,
6974 hdev->dev_class, 3);
6975 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006976 break;
6977 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006978 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6979 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006980 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006981 status = MGMT_STATUS_FAILED;
6982 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006983 }
6984
Marcel Holtmanne2135682015-04-02 12:00:58 -07006985 /* This should return the active RPA, but since the RPA
6986 * is only programmed on demand, it is really hard to fill
6987 * this in at the moment. For now disallow retrieving
6988 * local out-of-band data when privacy is in use.
6989 *
6990 * Returning the identity address will not help here since
6991 * pairing happens before the identity resolving key is
6992 * known and thus the connection establishment happens
6993 * based on the RPA and not the identity address.
6994 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006995 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006996 hci_dev_unlock(hdev);
6997 status = MGMT_STATUS_REJECTED;
6998 goto complete;
6999 }
7000
7001 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
7002 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
7003 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
7004 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007005 memcpy(addr, &hdev->static_addr, 6);
7006 addr[6] = 0x01;
7007 } else {
7008 memcpy(addr, &hdev->bdaddr, 6);
7009 addr[6] = 0x00;
7010 }
7011
7012 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
7013 addr, sizeof(addr));
7014
7015 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7016 role = 0x02;
7017 else
7018 role = 0x01;
7019
7020 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
7021 &role, sizeof(role));
7022
Marcel Holtmann5082a592015-03-16 12:39:00 -07007023 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
7024 eir_len = eir_append_data(rp->eir, eir_len,
7025 EIR_LE_SC_CONFIRM,
7026 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007027
Marcel Holtmann5082a592015-03-16 12:39:00 -07007028 eir_len = eir_append_data(rp->eir, eir_len,
7029 EIR_LE_SC_RANDOM,
7030 rand, sizeof(rand));
7031 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007032
Johan Hedbergf2252572015-11-18 12:49:20 +02007033 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007034
7035 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
7036 flags |= LE_AD_NO_BREDR;
7037
7038 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
7039 &flags, sizeof(flags));
7040 break;
7041 }
7042
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007043 hci_dev_unlock(hdev);
7044
Marcel Holtmann72000df2015-03-16 16:11:21 -07007045 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
7046
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007047 status = MGMT_STATUS_SUCCESS;
7048
7049complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07007050 rp->type = cp->type;
7051 rp->eir_len = cpu_to_le16(eir_len);
7052
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007053 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07007054 status, rp, sizeof(*rp) + eir_len);
7055 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07007056 goto done;
7057
7058 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
7059 rp, sizeof(*rp) + eir_len,
7060 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007061
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07007062done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007063 kfree(rp);
7064
7065 return err;
7066}
7067
Arman Uguray089fa8c2015-03-25 18:53:45 -07007068static u32 get_supported_adv_flags(struct hci_dev *hdev)
7069{
7070 u32 flags = 0;
7071
7072 flags |= MGMT_ADV_FLAG_CONNECTABLE;
7073 flags |= MGMT_ADV_FLAG_DISCOV;
7074 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
7075 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007076 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007077 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007078
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05307079 /* In extended adv TX_POWER returned from Set Adv Param
7080 * will be always valid.
7081 */
7082 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
7083 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07007084 flags |= MGMT_ADV_FLAG_TX_POWER;
7085
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307086 if (ext_adv_capable(hdev)) {
7087 flags |= MGMT_ADV_FLAG_SEC_1M;
7088
7089 if (hdev->le_features[1] & HCI_LE_PHY_2M)
7090 flags |= MGMT_ADV_FLAG_SEC_2M;
7091
7092 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
7093 flags |= MGMT_ADV_FLAG_SEC_CODED;
7094 }
7095
Arman Uguray089fa8c2015-03-25 18:53:45 -07007096 return flags;
7097}
7098
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007099static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7100 void *data, u16 data_len)
7101{
7102 struct mgmt_rp_read_adv_features *rp;
7103 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007104 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02007105 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07007106 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007107 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007108
Marcel Holtmann181d6952020-05-06 09:57:47 +02007109 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007110
Arman Uguray089fa8c2015-03-25 18:53:45 -07007111 if (!lmp_le_capable(hdev))
7112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7113 MGMT_STATUS_REJECTED);
7114
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007115 hci_dev_lock(hdev);
7116
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007117 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007118 rp = kmalloc(rp_len, GFP_ATOMIC);
7119 if (!rp) {
7120 hci_dev_unlock(hdev);
7121 return -ENOMEM;
7122 }
7123
Arman Uguray089fa8c2015-03-25 18:53:45 -07007124 supported_flags = get_supported_adv_flags(hdev);
7125
7126 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07007127 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
7128 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02007129 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007130 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07007131
Johan Hedberg02c04afe2015-11-26 12:15:58 +02007132 instance = rp->instance;
7133 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
7134 *instance = adv_instance->instance;
7135 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07007136 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007137
7138 hci_dev_unlock(hdev);
7139
7140 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
7141 MGMT_STATUS_SUCCESS, rp, rp_len);
7142
7143 kfree(rp);
7144
7145 return err;
7146}
7147
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007148static u8 calculate_name_len(struct hci_dev *hdev)
7149{
7150 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
7151
7152 return append_local_name(hdev, buf, 0);
7153}
7154
7155static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
7156 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07007157{
Arman Uguray4117ed72015-03-23 15:57:14 -07007158 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07007159
Marcel Holtmann31a32482015-11-19 16:16:42 +01007160 if (is_adv_data) {
7161 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7162 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02007163 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01007164 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07007165
Szymon Janc2bb368702016-09-18 12:50:05 +02007166 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01007167 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007168 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02007169 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007170 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007171
Szymon Janc2bb368702016-09-18 12:50:05 +02007172 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007173 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07007174 }
7175
Szymon Janc2bb368702016-09-18 12:50:05 +02007176 return max_len;
7177}
7178
7179static bool flags_managed(u32 adv_flags)
7180{
7181 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
7182 MGMT_ADV_FLAG_LIMITED_DISCOV |
7183 MGMT_ADV_FLAG_MANAGED_FLAGS);
7184}
7185
7186static bool tx_power_managed(u32 adv_flags)
7187{
7188 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
7189}
7190
7191static bool name_managed(u32 adv_flags)
7192{
7193 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
7194}
7195
7196static bool appearance_managed(u32 adv_flags)
7197{
7198 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
7199}
7200
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007201static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
7202 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02007203{
7204 int i, cur_len;
7205 u8 max_len;
7206
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007207 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02007208
Arman Uguray4117ed72015-03-23 15:57:14 -07007209 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007210 return false;
7211
Arman Uguray4117ed72015-03-23 15:57:14 -07007212 /* Make sure that the data is correctly formatted. */
7213 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
7214 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07007215
Szymon Janc9c9db782016-09-18 12:50:06 +02007216 if (data[i + 1] == EIR_FLAGS &&
7217 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07007218 return false;
7219
Szymon Janc2bb368702016-09-18 12:50:05 +02007220 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
7221 return false;
7222
7223 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
7224 return false;
7225
7226 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
7227 return false;
7228
7229 if (data[i + 1] == EIR_APPEARANCE &&
7230 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07007231 return false;
7232
Arman Uguray24b4f382015-03-23 15:57:12 -07007233 /* If the current field length would exceed the total data
7234 * length, then it's invalid.
7235 */
Arman Uguray4117ed72015-03-23 15:57:14 -07007236 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07007237 return false;
7238 }
7239
7240 return true;
7241}
7242
Arman Uguray24b4f382015-03-23 15:57:12 -07007243static void add_advertising_complete(struct hci_dev *hdev, u8 status,
7244 u16 opcode)
7245{
7246 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007247 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07007248 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007249 struct adv_info *adv_instance, *n;
7250 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007251
Marcel Holtmann181d6952020-05-06 09:57:47 +02007252 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07007253
7254 hci_dev_lock(hdev);
7255
7256 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
7257
Florian Grandelfffd38b2015-06-18 03:16:47 +02007258 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
7259 if (!adv_instance->pending)
7260 continue;
7261
7262 if (!status) {
7263 adv_instance->pending = false;
7264 continue;
7265 }
7266
7267 instance = adv_instance->instance;
7268
7269 if (hdev->cur_adv_instance == instance)
7270 cancel_adv_timeout(hdev);
7271
7272 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02007273 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007274 }
7275
7276 if (!cmd)
7277 goto unlock;
7278
Florian Grandelfffd38b2015-06-18 03:16:47 +02007279 cp = cmd->param;
7280 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007281
7282 if (status)
7283 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
7284 mgmt_status(status));
7285 else
7286 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
7287 mgmt_status(status), &rp, sizeof(rp));
7288
7289 mgmt_pending_remove(cmd);
7290
7291unlock:
7292 hci_dev_unlock(hdev);
7293}
7294
7295static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7296 void *data, u16 data_len)
7297{
7298 struct mgmt_cp_add_advertising *cp = data;
7299 struct mgmt_rp_add_advertising rp;
7300 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307301 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07007302 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02007303 u16 timeout, duration;
7304 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
7305 u8 schedule_instance = 0;
7306 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007307 int err;
7308 struct mgmt_pending_cmd *cmd;
7309 struct hci_request req;
7310
Marcel Holtmann181d6952020-05-06 09:57:47 +02007311 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07007312
7313 status = mgmt_le_support(hdev);
7314 if (status)
7315 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7316 status);
7317
Marcel Holtmannceff86a2015-11-19 16:16:41 +01007318 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7319 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7320 MGMT_STATUS_INVALID_PARAMS);
7321
Johan Hedberg6a0e7802016-03-11 09:56:33 +02007322 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
7323 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7324 MGMT_STATUS_INVALID_PARAMS);
7325
Arman Uguray24b4f382015-03-23 15:57:12 -07007326 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07007327 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02007328 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07007329
Florian Grandelfffd38b2015-06-18 03:16:47 +02007330 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307331 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07007332 */
7333 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05307334 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
7335 if (flags & ~supported_flags ||
7336 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07007337 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7338 MGMT_STATUS_INVALID_PARAMS);
7339
7340 hci_dev_lock(hdev);
7341
Arman Uguray912098a2015-03-23 15:57:15 -07007342 if (timeout && !hdev_is_powered(hdev)) {
7343 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7344 MGMT_STATUS_REJECTED);
7345 goto unlock;
7346 }
7347
Arman Uguray24b4f382015-03-23 15:57:12 -07007348 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007349 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07007350 pending_find(MGMT_OP_SET_LE, hdev)) {
7351 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7352 MGMT_STATUS_BUSY);
7353 goto unlock;
7354 }
7355
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007356 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
7357 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07007358 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07007359 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7360 MGMT_STATUS_INVALID_PARAMS);
7361 goto unlock;
7362 }
7363
Florian Grandelfffd38b2015-06-18 03:16:47 +02007364 err = hci_add_adv_instance(hdev, cp->instance, flags,
7365 cp->adv_data_len, cp->data,
7366 cp->scan_rsp_len,
7367 cp->data + cp->adv_data_len,
7368 timeout, duration);
7369 if (err < 0) {
7370 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7371 MGMT_STATUS_FAILED);
7372 goto unlock;
7373 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007374
Florian Grandelfffd38b2015-06-18 03:16:47 +02007375 /* Only trigger an advertising added event if a new instance was
7376 * actually added.
7377 */
7378 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02007379 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07007380
Florian Grandelfffd38b2015-06-18 03:16:47 +02007381 if (hdev->cur_adv_instance == cp->instance) {
7382 /* If the currently advertised instance is being changed then
7383 * cancel the current advertising and schedule the next
7384 * instance. If there is only one instance then the overridden
7385 * advertising data will be visible right away.
7386 */
7387 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007388
Florian Grandelfffd38b2015-06-18 03:16:47 +02007389 next_instance = hci_get_next_instance(hdev, cp->instance);
7390 if (next_instance)
7391 schedule_instance = next_instance->instance;
7392 } else if (!hdev->adv_instance_timeout) {
7393 /* Immediately advertise the new instance if no other
7394 * instance is currently being advertised.
7395 */
7396 schedule_instance = cp->instance;
7397 }
Arman Uguray912098a2015-03-23 15:57:15 -07007398
Florian Grandelfffd38b2015-06-18 03:16:47 +02007399 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7400 * there is no instance to be advertised then we have no HCI
7401 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007402 */
7403 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007404 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7405 !schedule_instance) {
7406 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7408 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7409 goto unlock;
7410 }
7411
7412 /* We're good to go, update advertising data, parameters, and start
7413 * advertising.
7414 */
7415 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7416 data_len);
7417 if (!cmd) {
7418 err = -ENOMEM;
7419 goto unlock;
7420 }
7421
7422 hci_req_init(&req, hdev);
7423
Johan Hedbergf2252572015-11-18 12:49:20 +02007424 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007425
Florian Grandelfffd38b2015-06-18 03:16:47 +02007426 if (!err)
7427 err = hci_req_run(&req, add_advertising_complete);
7428
Joseph Hwang72da7b22020-03-10 09:31:50 -07007429 if (err < 0) {
7430 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7431 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007432 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007433 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007434
7435unlock:
7436 hci_dev_unlock(hdev);
7437
7438 return err;
7439}
7440
Arman Ugurayda9293352015-03-23 15:57:13 -07007441static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7442 u16 opcode)
7443{
7444 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007445 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007446 struct mgmt_rp_remove_advertising rp;
7447
Marcel Holtmann181d6952020-05-06 09:57:47 +02007448 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007449
7450 hci_dev_lock(hdev);
7451
7452 /* A failure status here only means that we failed to disable
7453 * advertising. Otherwise, the advertising instance has been removed,
7454 * so report success.
7455 */
7456 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7457 if (!cmd)
7458 goto unlock;
7459
Florian Grandel01948332015-06-18 03:16:48 +02007460 cp = cmd->param;
7461 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007462
7463 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7464 &rp, sizeof(rp));
7465 mgmt_pending_remove(cmd);
7466
7467unlock:
7468 hci_dev_unlock(hdev);
7469}
7470
7471static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7472 void *data, u16 data_len)
7473{
7474 struct mgmt_cp_remove_advertising *cp = data;
7475 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007476 struct mgmt_pending_cmd *cmd;
7477 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007478 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007479
Marcel Holtmann181d6952020-05-06 09:57:47 +02007480 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007481
Arman Ugurayda9293352015-03-23 15:57:13 -07007482 hci_dev_lock(hdev);
7483
Johan Hedberg952497b2015-06-18 21:05:31 +03007484 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007485 err = mgmt_cmd_status(sk, hdev->id,
7486 MGMT_OP_REMOVE_ADVERTISING,
7487 MGMT_STATUS_INVALID_PARAMS);
7488 goto unlock;
7489 }
7490
Arman Ugurayda9293352015-03-23 15:57:13 -07007491 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7492 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7493 pending_find(MGMT_OP_SET_LE, hdev)) {
7494 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7495 MGMT_STATUS_BUSY);
7496 goto unlock;
7497 }
7498
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007499 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007500 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7501 MGMT_STATUS_INVALID_PARAMS);
7502 goto unlock;
7503 }
7504
Florian Grandel01948332015-06-18 03:16:48 +02007505 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007506
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007507 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007508
Florian Grandel01948332015-06-18 03:16:48 +02007509 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007510 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007511
Florian Grandel01948332015-06-18 03:16:48 +02007512 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7513 * flag is set or the device isn't powered then we have no HCI
7514 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007515 */
Florian Grandel01948332015-06-18 03:16:48 +02007516 if (skb_queue_empty(&req.cmd_q) ||
7517 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007518 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307519 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007520 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007521 err = mgmt_cmd_complete(sk, hdev->id,
7522 MGMT_OP_REMOVE_ADVERTISING,
7523 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7524 goto unlock;
7525 }
7526
7527 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7528 data_len);
7529 if (!cmd) {
7530 err = -ENOMEM;
7531 goto unlock;
7532 }
7533
Arman Ugurayda9293352015-03-23 15:57:13 -07007534 err = hci_req_run(&req, remove_advertising_complete);
7535 if (err < 0)
7536 mgmt_pending_remove(cmd);
7537
7538unlock:
7539 hci_dev_unlock(hdev);
7540
7541 return err;
7542}
7543
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007544static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7545 void *data, u16 data_len)
7546{
7547 struct mgmt_cp_get_adv_size_info *cp = data;
7548 struct mgmt_rp_get_adv_size_info rp;
7549 u32 flags, supported_flags;
7550 int err;
7551
Marcel Holtmann181d6952020-05-06 09:57:47 +02007552 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007553
7554 if (!lmp_le_capable(hdev))
7555 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7556 MGMT_STATUS_REJECTED);
7557
7558 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7559 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7560 MGMT_STATUS_INVALID_PARAMS);
7561
7562 flags = __le32_to_cpu(cp->flags);
7563
7564 /* The current implementation only supports a subset of the specified
7565 * flags.
7566 */
7567 supported_flags = get_supported_adv_flags(hdev);
7568 if (flags & ~supported_flags)
7569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7570 MGMT_STATUS_INVALID_PARAMS);
7571
7572 rp.instance = cp->instance;
7573 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007574 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7575 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007576
7577 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7578 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7579
7580 return err;
7581}
7582
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007583static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007584 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007585 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007586 HCI_MGMT_NO_HDEV |
7587 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007588 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007589 HCI_MGMT_NO_HDEV |
7590 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007591 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007592 HCI_MGMT_NO_HDEV |
7593 HCI_MGMT_UNTRUSTED },
7594 { read_controller_info, MGMT_READ_INFO_SIZE,
7595 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007596 { set_powered, MGMT_SETTING_SIZE },
7597 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7598 { set_connectable, MGMT_SETTING_SIZE },
7599 { set_fast_connectable, MGMT_SETTING_SIZE },
7600 { set_bondable, MGMT_SETTING_SIZE },
7601 { set_link_security, MGMT_SETTING_SIZE },
7602 { set_ssp, MGMT_SETTING_SIZE },
7603 { set_hs, MGMT_SETTING_SIZE },
7604 { set_le, MGMT_SETTING_SIZE },
7605 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7606 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7607 { add_uuid, MGMT_ADD_UUID_SIZE },
7608 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007609 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7610 HCI_MGMT_VAR_LEN },
7611 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7612 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007613 { disconnect, MGMT_DISCONNECT_SIZE },
7614 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7615 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7616 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7617 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7618 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7619 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7620 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7621 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7622 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7623 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7624 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007625 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7626 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7627 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007628 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7629 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7630 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7631 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7632 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7633 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7634 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7635 { set_advertising, MGMT_SETTING_SIZE },
7636 { set_bredr, MGMT_SETTING_SIZE },
7637 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7638 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7639 { set_secure_conn, MGMT_SETTING_SIZE },
7640 { set_debug_keys, MGMT_SETTING_SIZE },
7641 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007642 { load_irks, MGMT_LOAD_IRKS_SIZE,
7643 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007644 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7645 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7646 { add_device, MGMT_ADD_DEVICE_SIZE },
7647 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007648 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7649 HCI_MGMT_VAR_LEN },
7650 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007651 HCI_MGMT_NO_HDEV |
7652 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007653 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007654 HCI_MGMT_UNCONFIGURED |
7655 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007656 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7657 HCI_MGMT_UNCONFIGURED },
7658 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7659 HCI_MGMT_UNCONFIGURED },
7660 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7661 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007662 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007663 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007664 HCI_MGMT_NO_HDEV |
7665 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007666 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007667 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7668 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007669 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007670 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007671 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007672 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7673 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007674 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307675 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307676 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007677 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7678 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007679 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007680 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7681 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007682 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7683 HCI_MGMT_UNTRUSTED |
7684 HCI_MGMT_HDEV_OPTIONAL },
7685 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7686 HCI_MGMT_VAR_LEN |
7687 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007688 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7689 HCI_MGMT_UNTRUSTED },
7690 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7691 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007692 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7693 HCI_MGMT_UNTRUSTED },
7694 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7695 HCI_MGMT_VAR_LEN },
Abhishek Pandit-Subedi4c54bf22020-06-17 16:39:11 +02007696 { get_device_flags, MGMT_GET_DEVICE_FLAGS_SIZE },
7697 { set_device_flags, MGMT_SET_DEVICE_FLAGS_SIZE },
Miao-chen Choue5e1e7f2020-06-17 16:39:13 +02007698 { read_adv_mon_features, MGMT_READ_ADV_MONITOR_FEATURES_SIZE },
Miao-chen Choub1395532020-06-17 16:39:14 +02007699 { add_adv_patterns_monitor,MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE,
7700 HCI_MGMT_VAR_LEN },
Miao-chen Choubd2fbc62020-06-17 16:39:15 +02007701 { remove_adv_monitor, MGMT_REMOVE_ADV_MONITOR_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007702};
7703
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007704void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007705{
Marcel Holtmannced85542015-03-14 19:27:56 -07007706 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007707
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007708 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7709 return;
7710
Marcel Holtmannf9207332015-03-14 19:27:55 -07007711 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007712 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007713 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7714 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7715 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007716 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007717 } else {
7718 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7719 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007720 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007721 }
7722 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007723 case HCI_AMP:
7724 ev.type = 0x02;
7725 break;
7726 default:
7727 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007728 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007729
7730 ev.bus = hdev->bus;
7731
7732 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7733 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007734}
7735
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007736void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007737{
Marcel Holtmannced85542015-03-14 19:27:56 -07007738 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007739 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007740
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007741 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7742 return;
7743
Marcel Holtmannf9207332015-03-14 19:27:55 -07007744 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007745 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007746 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007747
Marcel Holtmannf9207332015-03-14 19:27:55 -07007748 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7749 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7750 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007751 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007752 } else {
7753 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7754 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007755 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007756 }
7757 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007758 case HCI_AMP:
7759 ev.type = 0x02;
7760 break;
7761 default:
7762 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007763 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007764
7765 ev.bus = hdev->bus;
7766
7767 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7768 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007769}
7770
Andre Guedes6046dc32014-02-26 20:21:51 -03007771/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007772static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007773{
7774 struct hci_conn_params *p;
7775
7776 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007777 /* Needed for AUTO_OFF case where might not "really"
7778 * have been powered off.
7779 */
7780 list_del_init(&p->action);
7781
7782 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007783 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007784 case HCI_AUTO_CONN_ALWAYS:
7785 list_add(&p->action, &hdev->pend_le_conns);
7786 break;
7787 case HCI_AUTO_CONN_REPORT:
7788 list_add(&p->action, &hdev->pend_le_reports);
7789 break;
7790 default:
7791 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007792 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007793 }
7794}
7795
Johan Hedberg2ff13892015-11-25 16:15:44 +02007796void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007797{
7798 struct cmd_lookup match = { NULL, hdev };
7799
Marcel Holtmann181d6952020-05-06 09:57:47 +02007800 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007801
Johan Hedberg2ff13892015-11-25 16:15:44 +02007802 hci_dev_lock(hdev);
7803
7804 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007805 restart_le_actions(hdev);
7806 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007807 }
7808
Johan Hedberg229ab392013-03-15 17:06:53 -05007809 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7810
7811 new_settings(hdev, match.sk);
7812
Johan Hedberg229ab392013-03-15 17:06:53 -05007813 if (match.sk)
7814 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007815
7816 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007817}
7818
Johan Hedberg2ff13892015-11-25 16:15:44 +02007819void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007820{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007821 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007822 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007823
Johan Hedberg229ab392013-03-15 17:06:53 -05007824 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007825
7826 /* If the power off is because of hdev unregistration let
7827 * use the appropriate INVALID_INDEX status. Otherwise use
7828 * NOT_POWERED. We cover both scenarios here since later in
7829 * mgmt_index_removed() any hci_conn callbacks will have already
7830 * been triggered, potentially causing misleading DISCONNECTED
7831 * status responses.
7832 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007833 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007834 status = MGMT_STATUS_INVALID_INDEX;
7835 else
7836 status = MGMT_STATUS_NOT_POWERED;
7837
7838 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007839
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007840 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007841 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7842 zero_cod, sizeof(zero_cod),
7843 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007844 ext_info_changed(hdev, NULL);
7845 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007846
Johan Hedberg2ff13892015-11-25 16:15:44 +02007847 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007848
7849 if (match.sk)
7850 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007851}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007852
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007853void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007854{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007855 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007856 u8 status;
7857
Johan Hedberg333ae952015-03-17 13:48:47 +02007858 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007859 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007860 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007861
7862 if (err == -ERFKILL)
7863 status = MGMT_STATUS_RFKILLED;
7864 else
7865 status = MGMT_STATUS_FAILED;
7866
Johan Hedberga69e8372015-03-06 21:08:53 +02007867 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007868
7869 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007870}
7871
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007872void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7873 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007874{
Johan Hedberg86742e12011-11-07 23:13:38 +02007875 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007876
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007877 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007878
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007879 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007880 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007881 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007882 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007883 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007884 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007885
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007886 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007887}
Johan Hedbergf7520542011-01-20 12:34:39 +02007888
Johan Hedbergd7b25452014-05-23 13:19:53 +03007889static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7890{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007891 switch (ltk->type) {
7892 case SMP_LTK:
7893 case SMP_LTK_SLAVE:
7894 if (ltk->authenticated)
7895 return MGMT_LTK_AUTHENTICATED;
7896 return MGMT_LTK_UNAUTHENTICATED;
7897 case SMP_LTK_P256:
7898 if (ltk->authenticated)
7899 return MGMT_LTK_P256_AUTH;
7900 return MGMT_LTK_P256_UNAUTH;
7901 case SMP_LTK_P256_DEBUG:
7902 return MGMT_LTK_P256_DEBUG;
7903 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007904
7905 return MGMT_LTK_UNAUTHENTICATED;
7906}
7907
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007908void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007909{
7910 struct mgmt_ev_new_long_term_key ev;
7911
7912 memset(&ev, 0, sizeof(ev));
7913
Marcel Holtmann5192d302014-02-19 17:11:58 -08007914 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007915 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007916 * to store long term keys. Their addresses will change the
7917 * next time around.
7918 *
7919 * Only when a remote device provides an identity address
7920 * make sure the long term key is stored. If the remote
7921 * identity is known, the long term keys are internally
7922 * mapped to the identity address. So allow static random
7923 * and public addresses here.
7924 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007925 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7926 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7927 ev.store_hint = 0x00;
7928 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007929 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007930
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007931 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007932 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007933 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007934 ev.key.enc_size = key->enc_size;
7935 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007936 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007937
Johan Hedberg2ceba532014-06-16 19:25:16 +03007938 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007939 ev.key.master = 1;
7940
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007941 /* Make sure we copy only the significant bytes based on the
7942 * encryption key size, and set the rest of the value to zeroes.
7943 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007944 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007945 memset(ev.key.val + key->enc_size, 0,
7946 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007947
Marcel Holtmann083368f2013-10-15 14:26:29 -07007948 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007949}
7950
Johan Hedbergcad20c22015-10-12 13:36:19 +02007951void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007952{
7953 struct mgmt_ev_new_irk ev;
7954
7955 memset(&ev, 0, sizeof(ev));
7956
Johan Hedbergcad20c22015-10-12 13:36:19 +02007957 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007958
Johan Hedberg95fbac82014-02-19 15:18:31 +02007959 bacpy(&ev.rpa, &irk->rpa);
7960 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7961 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7962 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7963
7964 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7965}
7966
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007967void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7968 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007969{
7970 struct mgmt_ev_new_csrk ev;
7971
7972 memset(&ev, 0, sizeof(ev));
7973
7974 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007975 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007976 * to store signature resolving keys. Their addresses will change
7977 * the next time around.
7978 *
7979 * Only when a remote device provides an identity address
7980 * make sure the signature resolving key is stored. So allow
7981 * static random and public addresses here.
7982 */
7983 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7984 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7985 ev.store_hint = 0x00;
7986 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007987 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007988
7989 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7990 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007991 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007992 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7993
7994 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7995}
7996
Andre Guedesffb5a8272014-07-01 18:10:11 -03007997void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007998 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7999 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03008000{
8001 struct mgmt_ev_new_conn_param ev;
8002
Johan Hedbergc103aea2014-07-02 17:37:34 +03008003 if (!hci_is_identity_address(bdaddr, bdaddr_type))
8004 return;
8005
Andre Guedesffb5a8272014-07-01 18:10:11 -03008006 memset(&ev, 0, sizeof(ev));
8007 bacpy(&ev.addr.bdaddr, bdaddr);
8008 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03008009 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03008010 ev.min_interval = cpu_to_le16(min_interval);
8011 ev.max_interval = cpu_to_le16(max_interval);
8012 ev.latency = cpu_to_le16(latency);
8013 ev.timeout = cpu_to_le16(timeout);
8014
8015 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
8016}
8017
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008018void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
8019 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02008020{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008021 char buf[512];
8022 struct mgmt_ev_device_connected *ev = (void *) buf;
8023 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02008024
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00008025 bacpy(&ev->addr.bdaddr, &conn->dst);
8026 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02008027
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02008028 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02008029
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008030 /* We must ensure that the EIR Data fields are ordered and
8031 * unique. Keep it simple for now and avoid the problem by not
8032 * adding any BR/EDR data to the LE adv.
8033 */
8034 if (conn->le_adv_data_len > 0) {
8035 memcpy(&ev->eir[eir_len],
8036 conn->le_adv_data, conn->le_adv_data_len);
8037 eir_len = conn->le_adv_data_len;
8038 } else {
8039 if (name_len > 0)
8040 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
8041 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008042
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00008043 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00008044 eir_len = eir_append_data(ev->eir, eir_len,
8045 EIR_CLASS_OF_DEV,
8046 conn->dev_class, 3);
8047 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02008048
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008049 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008050
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07008051 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
8052 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02008053}
8054
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008055static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008056{
Johan Hedberg8962ee72011-01-20 12:40:27 +02008057 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008058
Johan Hedbergf5818c22014-12-05 13:36:02 +02008059 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008060
8061 *sk = cmd->sk;
8062 sock_hold(*sk);
8063
Johan Hedberga664b5b2011-02-19 12:06:02 -03008064 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008065}
8066
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008067static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02008068{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008069 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02008070 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02008071
Johan Hedbergb1078ad2012-02-09 17:21:16 +02008072 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
8073
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02008074 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02008075 mgmt_pending_remove(cmd);
8076}
8077
Johan Hedberg84c61d92014-08-01 11:13:30 +03008078bool mgmt_powering_down(struct hci_dev *hdev)
8079{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008080 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03008081 struct mgmt_mode *cp;
8082
Johan Hedberg333ae952015-03-17 13:48:47 +02008083 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03008084 if (!cmd)
8085 return false;
8086
8087 cp = cmd->param;
8088 if (!cp->val)
8089 return true;
8090
8091 return false;
8092}
8093
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008094void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008095 u8 link_type, u8 addr_type, u8 reason,
8096 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02008097{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008098 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008099 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008100
Johan Hedberg84c61d92014-08-01 11:13:30 +03008101 /* The connection is still in hci_conn_hash so test for 1
8102 * instead of 0 to know if this is the last one.
8103 */
8104 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8105 cancel_delayed_work(&hdev->power_off);
8106 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02008107 }
8108
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02008109 if (!mgmt_connected)
8110 return;
8111
Andre Guedes57eb7762013-10-30 19:01:41 -03008112 if (link_type != ACL_LINK && link_type != LE_LINK)
8113 return;
8114
Johan Hedberg744cf192011-11-08 20:40:14 +02008115 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02008116
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02008117 bacpy(&ev.addr.bdaddr, bdaddr);
8118 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8119 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02008120
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07008121 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008122
8123 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01008124 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008125
Johan Hedberg124f6e32012-02-09 13:50:12 +02008126 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008127 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008128}
8129
Marcel Holtmann78929242013-10-06 23:55:47 -07008130void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
8131 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02008132{
Andre Guedes3655bba2013-10-30 19:01:40 -03008133 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
8134 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008135 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008136
Jefferson Delfes36a75f12012-09-18 13:36:54 -04008137 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
8138 hdev);
8139
Johan Hedberg333ae952015-03-17 13:48:47 +02008140 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02008141 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07008142 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02008143
Andre Guedes3655bba2013-10-30 19:01:40 -03008144 cp = cmd->param;
8145
8146 if (bacmp(bdaddr, &cp->addr.bdaddr))
8147 return;
8148
8149 if (cp->addr.type != bdaddr_type)
8150 return;
8151
Johan Hedbergf5818c22014-12-05 13:36:02 +02008152 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008153 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02008154}
Johan Hedberg17d5c042011-01-22 06:09:08 +02008155
Marcel Holtmann445608d2013-10-06 23:55:48 -07008156void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8157 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02008158{
8159 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02008160
Johan Hedberg84c61d92014-08-01 11:13:30 +03008161 /* The connection is still in hci_conn_hash so test for 1
8162 * instead of 0 to know if this is the last one.
8163 */
8164 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
8165 cancel_delayed_work(&hdev->power_off);
8166 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02008167 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02008168
Johan Hedberg4c659c32011-11-07 23:13:39 +02008169 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008170 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02008171 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008172
Marcel Holtmann445608d2013-10-06 23:55:48 -07008173 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02008174}
Johan Hedberg980e1a52011-01-22 06:10:07 +02008175
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008176void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008177{
8178 struct mgmt_ev_pin_code_request ev;
8179
Johan Hedbergd8457692012-02-17 14:24:57 +02008180 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03008181 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02008182 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008183
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07008184 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008185}
8186
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008187void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8188 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008189{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008190 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008191
Johan Hedberg333ae952015-03-17 13:48:47 +02008192 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008193 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07008194 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008195
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008196 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008197 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008198}
8199
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008200void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
8201 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02008202{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008203 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008204
Johan Hedberg333ae952015-03-17 13:48:47 +02008205 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008206 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07008207 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02008208
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008209 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008210 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02008211}
Johan Hedberga5c29682011-02-19 12:05:57 -03008212
Johan Hedberg744cf192011-11-08 20:40:14 +02008213int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02008214 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008215 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03008216{
8217 struct mgmt_ev_user_confirm_request ev;
8218
Marcel Holtmann181d6952020-05-06 09:57:47 +02008219 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03008220
Johan Hedberg272d90d2012-02-09 15:26:12 +02008221 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008222 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07008223 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02008224 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03008225
Johan Hedberg744cf192011-11-08 20:40:14 +02008226 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008227 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03008228}
8229
Johan Hedberg272d90d2012-02-09 15:26:12 +02008230int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008231 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08008232{
8233 struct mgmt_ev_user_passkey_request ev;
8234
Marcel Holtmann181d6952020-05-06 09:57:47 +02008235 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08008236
Johan Hedberg272d90d2012-02-09 15:26:12 +02008237 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008238 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08008239
8240 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008241 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08008242}
8243
Brian Gix0df4c182011-11-16 13:53:13 -08008244static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03008245 u8 link_type, u8 addr_type, u8 status,
8246 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03008247{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008248 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03008249
Johan Hedberg333ae952015-03-17 13:48:47 +02008250 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03008251 if (!cmd)
8252 return -ENOENT;
8253
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008254 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03008255 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03008256
Johan Hedberg7776d1d2014-12-05 13:36:03 +02008257 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03008258}
8259
Johan Hedberg744cf192011-11-08 20:40:14 +02008260int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008261 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008262{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008263 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008264 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008265}
8266
Johan Hedberg272d90d2012-02-09 15:26:12 +02008267int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008268 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03008269{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008270 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008271 status,
8272 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03008273}
Johan Hedberg2a611692011-02-19 12:06:00 -03008274
Brian Gix604086b2011-11-23 08:28:33 -08008275int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008276 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008277{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008278 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008279 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008280}
8281
Johan Hedberg272d90d2012-02-09 15:26:12 +02008282int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008283 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08008284{
Johan Hedberg272d90d2012-02-09 15:26:12 +02008285 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03008286 status,
8287 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08008288}
8289
Johan Hedberg92a25252012-09-06 18:39:26 +03008290int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
8291 u8 link_type, u8 addr_type, u32 passkey,
8292 u8 entered)
8293{
8294 struct mgmt_ev_passkey_notify ev;
8295
Marcel Holtmann181d6952020-05-06 09:57:47 +02008296 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03008297
8298 bacpy(&ev.addr.bdaddr, bdaddr);
8299 ev.addr.type = link_to_bdaddr(link_type, addr_type);
8300 ev.passkey = __cpu_to_le32(passkey);
8301 ev.entered = entered;
8302
8303 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
8304}
8305
Johan Hedberge1e930f2014-09-08 17:09:49 -07008306void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03008307{
8308 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008309 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07008310 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03008311
Johan Hedberge1e930f2014-09-08 17:09:49 -07008312 bacpy(&ev.addr.bdaddr, &conn->dst);
8313 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
8314 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03008315
Johan Hedberge1e930f2014-09-08 17:09:49 -07008316 cmd = find_pairing(conn);
8317
8318 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
8319 cmd ? cmd->sk : NULL);
8320
Johan Hedberga511b352014-12-11 21:45:45 +02008321 if (cmd) {
8322 cmd->cmd_complete(cmd, status);
8323 mgmt_pending_remove(cmd);
8324 }
Johan Hedberg2a611692011-02-19 12:06:00 -03008325}
Johan Hedbergb312b1612011-03-16 14:29:37 +02008326
Marcel Holtmann464996a2013-10-15 14:26:24 -07008327void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008328{
8329 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07008330 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008331
8332 if (status) {
8333 u8 mgmt_err = mgmt_status(status);
8334 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008335 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008336 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008337 }
8338
Marcel Holtmann464996a2013-10-15 14:26:24 -07008339 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008340 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008341 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008342 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008343
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008344 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008345 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008346
Johan Hedberg47990ea2012-02-22 11:58:37 +02008347 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008348 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008349
8350 if (match.sk)
8351 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008352}
8353
Johan Hedberg890ea892013-03-15 17:06:52 -05008354static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008355{
Johan Hedberg890ea892013-03-15 17:06:52 -05008356 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008357 struct hci_cp_write_eir cp;
8358
Johan Hedberg976eb202012-10-24 21:12:01 +03008359 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008360 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008361
Johan Hedbergc80da272012-02-22 15:38:48 +02008362 memset(hdev->eir, 0, sizeof(hdev->eir));
8363
Johan Hedbergcacaf522012-02-21 00:52:42 +02008364 memset(&cp, 0, sizeof(cp));
8365
Johan Hedberg890ea892013-03-15 17:06:52 -05008366 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008367}
8368
Marcel Holtmann3e248562013-10-15 14:26:25 -07008369void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008370{
8371 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008372 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008373 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008374
8375 if (status) {
8376 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008377
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008378 if (enable && hci_dev_test_and_clear_flag(hdev,
8379 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008380 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008381 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008382 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008383
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008384 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8385 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008386 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008387 }
8388
8389 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008390 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008391 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008392 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008393 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008394 changed = hci_dev_test_and_clear_flag(hdev,
8395 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008396 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008397 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008398 }
8399
8400 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8401
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008402 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008403 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008404
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008405 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008406 sock_put(match.sk);
8407
Johan Hedberg890ea892013-03-15 17:06:52 -05008408 hci_req_init(&req, hdev);
8409
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008410 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8411 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008412 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8413 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008414 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008415 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008416 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008417 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008418
8419 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008420}
8421
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008422static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008423{
8424 struct cmd_lookup *match = data;
8425
Johan Hedberg90e70452012-02-23 23:09:40 +02008426 if (match->sk == NULL) {
8427 match->sk = cmd->sk;
8428 sock_hold(match->sk);
8429 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008430}
8431
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008432void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8433 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008434{
Johan Hedberg90e70452012-02-23 23:09:40 +02008435 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008436
Johan Hedberg92da6092013-03-15 17:06:55 -05008437 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8438 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8439 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008440
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008441 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008442 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8443 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008444 ext_info_changed(hdev, NULL);
8445 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008446
8447 if (match.sk)
8448 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008449}
8450
Marcel Holtmann7667da32013-10-15 14:26:27 -07008451void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008452{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008453 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008454 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008455
Johan Hedberg13928972013-03-15 17:07:00 -05008456 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008457 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008458
8459 memset(&ev, 0, sizeof(ev));
8460 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008461 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008462
Johan Hedberg333ae952015-03-17 13:48:47 +02008463 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008464 if (!cmd) {
8465 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008466
Johan Hedberg13928972013-03-15 17:07:00 -05008467 /* If this is a HCI command related to powering on the
8468 * HCI dev don't send any mgmt signals.
8469 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008470 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008471 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008472 }
8473
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008474 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8475 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008476 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008477}
Szymon Jancc35938b2011-03-22 13:12:21 +01008478
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008479static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8480{
8481 int i;
8482
8483 for (i = 0; i < uuid_count; i++) {
8484 if (!memcmp(uuid, uuids[i], 16))
8485 return true;
8486 }
8487
8488 return false;
8489}
8490
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008491static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8492{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008493 u16 parsed = 0;
8494
8495 while (parsed < eir_len) {
8496 u8 field_len = eir[0];
8497 u8 uuid[16];
8498 int i;
8499
8500 if (field_len == 0)
8501 break;
8502
8503 if (eir_len - parsed < field_len + 1)
8504 break;
8505
8506 switch (eir[1]) {
8507 case EIR_UUID16_ALL:
8508 case EIR_UUID16_SOME:
8509 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008510 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008511 uuid[13] = eir[i + 3];
8512 uuid[12] = eir[i + 2];
8513 if (has_uuid(uuid, uuid_count, uuids))
8514 return true;
8515 }
8516 break;
8517 case EIR_UUID32_ALL:
8518 case EIR_UUID32_SOME:
8519 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008520 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008521 uuid[15] = eir[i + 5];
8522 uuid[14] = eir[i + 4];
8523 uuid[13] = eir[i + 3];
8524 uuid[12] = eir[i + 2];
8525 if (has_uuid(uuid, uuid_count, uuids))
8526 return true;
8527 }
8528 break;
8529 case EIR_UUID128_ALL:
8530 case EIR_UUID128_SOME:
8531 for (i = 0; i + 17 <= field_len; i += 16) {
8532 memcpy(uuid, eir + i + 2, 16);
8533 if (has_uuid(uuid, uuid_count, uuids))
8534 return true;
8535 }
8536 break;
8537 }
8538
8539 parsed += field_len + 1;
8540 eir += field_len + 1;
8541 }
8542
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008543 return false;
8544}
8545
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008546static void restart_le_scan(struct hci_dev *hdev)
8547{
8548 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008549 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008550 return;
8551
8552 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8553 hdev->discovery.scan_start +
8554 hdev->discovery.scan_duration))
8555 return;
8556
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008557 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008558 DISCOV_LE_RESTART_DELAY);
8559}
8560
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008561static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8562 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8563{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008564 /* If a RSSI threshold has been specified, and
8565 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8566 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8567 * is set, let it through for further processing, as we might need to
8568 * restart the scan.
8569 *
8570 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8571 * the results are also dropped.
8572 */
8573 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8574 (rssi == HCI_RSSI_INVALID ||
8575 (rssi < hdev->discovery.rssi &&
8576 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8577 return false;
8578
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008579 if (hdev->discovery.uuid_count != 0) {
8580 /* If a list of UUIDs is provided in filter, results with no
8581 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008582 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008583 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8584 hdev->discovery.uuids) &&
8585 !eir_has_uuids(scan_rsp, scan_rsp_len,
8586 hdev->discovery.uuid_count,
8587 hdev->discovery.uuids))
8588 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008589 }
8590
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008591 /* If duplicate filtering does not report RSSI changes, then restart
8592 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008593 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008594 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8595 restart_le_scan(hdev);
8596
8597 /* Validate RSSI value against the RSSI threshold once more. */
8598 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8599 rssi < hdev->discovery.rssi)
8600 return false;
8601 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008602
8603 return true;
8604}
8605
Marcel Holtmann901801b2013-10-06 23:55:51 -07008606void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008607 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8608 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008609{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008610 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008611 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008612 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008613
Johan Hedberg75ce2082014-07-02 22:42:01 +03008614 /* Don't send events for a non-kernel initiated discovery. With
8615 * LE one exception is if we have pend_le_reports > 0 in which
8616 * case we're doing passive scanning and want these events.
8617 */
8618 if (!hci_discovery_active(hdev)) {
8619 if (link_type == ACL_LINK)
8620 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008621 if (link_type == LE_LINK &&
8622 list_empty(&hdev->pend_le_reports) &&
8623 !hci_is_adv_monitoring(hdev)) {
Johan Hedberg75ce2082014-07-02 22:42:01 +03008624 return;
Miao-chen Chou8208f5a2020-06-17 16:39:18 +02008625 }
Johan Hedberg75ce2082014-07-02 22:42:01 +03008626 }
Andre Guedes12602d02013-04-30 15:29:40 -03008627
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008628 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008629 /* We are using service discovery */
8630 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8631 scan_rsp_len))
8632 return;
8633 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008634
Johan Hedberg78b781c2016-01-05 13:19:32 +02008635 if (hdev->discovery.limited) {
8636 /* Check for limited discoverable bit */
8637 if (dev_class) {
8638 if (!(dev_class[1] & 0x20))
8639 return;
8640 } else {
8641 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8642 if (!flags || !(flags[0] & LE_AD_LIMITED))
8643 return;
8644 }
8645 }
8646
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008647 /* Make sure that the buffer is big enough. The 5 extra bytes
8648 * are for the potential CoD field.
8649 */
8650 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008651 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008652
Johan Hedberg1dc06092012-01-15 21:01:23 +02008653 memset(buf, 0, sizeof(buf));
8654
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008655 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8656 * RSSI value was reported as 0 when not available. This behavior
8657 * is kept when using device discovery. This is required for full
8658 * backwards compatibility with the API.
8659 *
8660 * However when using service discovery, the value 127 will be
8661 * returned when the RSSI is not available.
8662 */
Szymon Janc91200e92015-01-22 16:57:05 +01008663 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8664 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008665 rssi = 0;
8666
Johan Hedberg841c5642014-07-07 12:45:54 +03008667 bacpy(&ev->addr.bdaddr, bdaddr);
8668 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008669 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008670 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008671
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008672 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008673 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008674 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008675
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008676 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8677 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008678 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008679 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008680
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008681 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008682 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008683 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008684
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008685 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8686 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008687
Marcel Holtmann901801b2013-10-06 23:55:51 -07008688 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008689}
Johan Hedberga88a9652011-03-30 13:18:12 +03008690
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008691void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8692 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008693{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008694 struct mgmt_ev_device_found *ev;
8695 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8696 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008697
Johan Hedbergb644ba32012-01-17 21:48:47 +02008698 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008699
Johan Hedbergb644ba32012-01-17 21:48:47 +02008700 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008701
Johan Hedbergb644ba32012-01-17 21:48:47 +02008702 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008703 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008704 ev->rssi = rssi;
8705
8706 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008707 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008708
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008709 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008710
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008711 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008712}
Johan Hedberg314b2382011-04-27 10:29:57 -04008713
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008714void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008715{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008716 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008717
Marcel Holtmann181d6952020-05-06 09:57:47 +02008718 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008719
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008720 memset(&ev, 0, sizeof(ev));
8721 ev.type = hdev->discovery.type;
8722 ev.discovering = discovering;
8723
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008724 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008725}
Antti Julku5e762442011-08-25 16:48:02 +03008726
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008727static struct hci_mgmt_chan chan = {
8728 .channel = HCI_CHANNEL_CONTROL,
8729 .handler_count = ARRAY_SIZE(mgmt_handlers),
8730 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008731 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008732};
8733
8734int mgmt_init(void)
8735{
8736 return hci_mgmt_chan_register(&chan);
8737}
8738
8739void mgmt_exit(void)
8740{
8741 hci_mgmt_chan_unregister(&chan);
8742}