blob: ecfdfc4df48602fac9b5c20daf40f05587c22237 [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"
Johan Hedberg03811012010-12-08 00:21:06 +020040
Johan Hedberg2da9c552012-02-17 14:39:28 +020041#define MGMT_VERSION 1
Marcel Holtmann3679fe72020-04-03 21:44:06 +020042#define MGMT_REVISION 17
Johan Hedberg02d98122010-12-13 21:07:04 +020043
Johan Hedberge70bb2e2012-02-13 16:59:33 +020044static const u16 mgmt_commands[] = {
45 MGMT_OP_READ_INDEX_LIST,
46 MGMT_OP_READ_INFO,
47 MGMT_OP_SET_POWERED,
48 MGMT_OP_SET_DISCOVERABLE,
49 MGMT_OP_SET_CONNECTABLE,
50 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030051 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020052 MGMT_OP_SET_LINK_SECURITY,
53 MGMT_OP_SET_SSP,
54 MGMT_OP_SET_HS,
55 MGMT_OP_SET_LE,
56 MGMT_OP_SET_DEV_CLASS,
57 MGMT_OP_SET_LOCAL_NAME,
58 MGMT_OP_ADD_UUID,
59 MGMT_OP_REMOVE_UUID,
60 MGMT_OP_LOAD_LINK_KEYS,
61 MGMT_OP_LOAD_LONG_TERM_KEYS,
62 MGMT_OP_DISCONNECT,
63 MGMT_OP_GET_CONNECTIONS,
64 MGMT_OP_PIN_CODE_REPLY,
65 MGMT_OP_PIN_CODE_NEG_REPLY,
66 MGMT_OP_SET_IO_CAPABILITY,
67 MGMT_OP_PAIR_DEVICE,
68 MGMT_OP_CANCEL_PAIR_DEVICE,
69 MGMT_OP_UNPAIR_DEVICE,
70 MGMT_OP_USER_CONFIRM_REPLY,
71 MGMT_OP_USER_CONFIRM_NEG_REPLY,
72 MGMT_OP_USER_PASSKEY_REPLY,
73 MGMT_OP_USER_PASSKEY_NEG_REPLY,
74 MGMT_OP_READ_LOCAL_OOB_DATA,
75 MGMT_OP_ADD_REMOTE_OOB_DATA,
76 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
77 MGMT_OP_START_DISCOVERY,
78 MGMT_OP_STOP_DISCOVERY,
79 MGMT_OP_CONFIRM_NAME,
80 MGMT_OP_BLOCK_DEVICE,
81 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070082 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030083 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030084 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070085 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070086 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080087 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080088 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020089 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020090 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020091 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030092 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020093 MGMT_OP_ADD_DEVICE,
94 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030095 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020096 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020097 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020098 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020099 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +0100100 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700101 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700102 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700103 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700104 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700105 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100106 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200107 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200108 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200109 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000110 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000111 MGMT_OP_SET_WIDEBAND_SPEECH,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200112 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200113 MGMT_OP_READ_EXP_FEATURES_INFO,
114 MGMT_OP_SET_EXP_FEATURE,
Alain Michaud17896402020-06-11 02:01:57 +0000115 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
116 MGMT_OP_SET_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200117 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
118 MGMT_OP_SET_DEF_RUNTIME_CONFIG,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200119};
120
121static const u16 mgmt_events[] = {
122 MGMT_EV_CONTROLLER_ERROR,
123 MGMT_EV_INDEX_ADDED,
124 MGMT_EV_INDEX_REMOVED,
125 MGMT_EV_NEW_SETTINGS,
126 MGMT_EV_CLASS_OF_DEV_CHANGED,
127 MGMT_EV_LOCAL_NAME_CHANGED,
128 MGMT_EV_NEW_LINK_KEY,
129 MGMT_EV_NEW_LONG_TERM_KEY,
130 MGMT_EV_DEVICE_CONNECTED,
131 MGMT_EV_DEVICE_DISCONNECTED,
132 MGMT_EV_CONNECT_FAILED,
133 MGMT_EV_PIN_CODE_REQUEST,
134 MGMT_EV_USER_CONFIRM_REQUEST,
135 MGMT_EV_USER_PASSKEY_REQUEST,
136 MGMT_EV_AUTH_FAILED,
137 MGMT_EV_DEVICE_FOUND,
138 MGMT_EV_DISCOVERING,
139 MGMT_EV_DEVICE_BLOCKED,
140 MGMT_EV_DEVICE_UNBLOCKED,
141 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300142 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800143 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700144 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200145 MGMT_EV_DEVICE_ADDED,
146 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300147 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200148 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200149 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200150 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700151 MGMT_EV_EXT_INDEX_ADDED,
152 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700153 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700154 MGMT_EV_ADVERTISING_ADDED,
155 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200156 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann5f4b9172020-05-06 09:57:46 +0200157 MGMT_EV_PHY_CONFIGURATION_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200158 MGMT_EV_EXP_FEATURE_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200159};
160
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700161static const u16 mgmt_untrusted_commands[] = {
162 MGMT_OP_READ_INDEX_LIST,
163 MGMT_OP_READ_INFO,
164 MGMT_OP_READ_UNCONF_INDEX_LIST,
165 MGMT_OP_READ_CONFIG_INFO,
166 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200167 MGMT_OP_READ_EXT_INFO,
Marcel Holtmannbc292252020-04-03 21:44:05 +0200168 MGMT_OP_READ_SECURITY_INFO,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200169 MGMT_OP_READ_EXP_FEATURES_INFO,
Alain Michaud17896402020-06-11 02:01:57 +0000170 MGMT_OP_READ_DEF_SYSTEM_CONFIG,
Marcel Holtmannaececa62020-06-17 16:39:07 +0200171 MGMT_OP_READ_DEF_RUNTIME_CONFIG,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700172};
173
174static const u16 mgmt_untrusted_events[] = {
175 MGMT_EV_INDEX_ADDED,
176 MGMT_EV_INDEX_REMOVED,
177 MGMT_EV_NEW_SETTINGS,
178 MGMT_EV_CLASS_OF_DEV_CHANGED,
179 MGMT_EV_LOCAL_NAME_CHANGED,
180 MGMT_EV_UNCONF_INDEX_ADDED,
181 MGMT_EV_UNCONF_INDEX_REMOVED,
182 MGMT_EV_NEW_CONFIG_OPTIONS,
183 MGMT_EV_EXT_INDEX_ADDED,
184 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200185 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmanna10c9072020-05-06 09:57:51 +0200186 MGMT_EV_EXP_FEATURE_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700187};
188
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800189#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200190
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200191#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
192 "\x00\x00\x00\x00\x00\x00\x00\x00"
193
Johan Hedbergca69b792011-11-11 18:10:00 +0200194/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000195static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200196 MGMT_STATUS_SUCCESS,
197 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
198 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
199 MGMT_STATUS_FAILED, /* Hardware Failure */
200 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
201 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200202 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200203 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
204 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
205 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
206 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
207 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
208 MGMT_STATUS_BUSY, /* Command Disallowed */
209 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
210 MGMT_STATUS_REJECTED, /* Rejected Security */
211 MGMT_STATUS_REJECTED, /* Rejected Personal */
212 MGMT_STATUS_TIMEOUT, /* Host Timeout */
213 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
214 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
215 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
216 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
217 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
218 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
219 MGMT_STATUS_BUSY, /* Repeated Attempts */
220 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
221 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
222 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
223 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
224 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
225 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
226 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
227 MGMT_STATUS_FAILED, /* Unspecified Error */
228 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
229 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
230 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
231 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
232 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
233 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
234 MGMT_STATUS_FAILED, /* Unit Link Key Used */
235 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
236 MGMT_STATUS_TIMEOUT, /* Instant Passed */
237 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
238 MGMT_STATUS_FAILED, /* Transaction Collision */
239 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
240 MGMT_STATUS_REJECTED, /* QoS Rejected */
241 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
242 MGMT_STATUS_REJECTED, /* Insufficient Security */
243 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
244 MGMT_STATUS_BUSY, /* Role Switch Pending */
245 MGMT_STATUS_FAILED, /* Slot Violation */
246 MGMT_STATUS_FAILED, /* Role Switch Failed */
247 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
248 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
249 MGMT_STATUS_BUSY, /* Host Busy Pairing */
250 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
251 MGMT_STATUS_BUSY, /* Controller Busy */
252 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
253 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
254 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
255 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
256 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
257};
258
259static u8 mgmt_status(u8 hci_status)
260{
261 if (hci_status < ARRAY_SIZE(mgmt_status_table))
262 return mgmt_status_table[hci_status];
263
264 return MGMT_STATUS_FAILED;
265}
266
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700267static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
268 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700269{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700270 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
271 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700272}
273
Marcel Holtmann72000df2015-03-16 16:11:21 -0700274static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
275 u16 len, int flag, struct sock *skip_sk)
276{
277 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
278 flag, skip_sk);
279}
280
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200281static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
282 struct sock *skip_sk)
283{
284 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700285 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200286}
287
Johan Hedberg85813a72015-10-21 18:02:59 +0300288static u8 le_addr_type(u8 mgmt_addr_type)
289{
290 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
291 return ADDR_LE_DEV_PUBLIC;
292 else
293 return ADDR_LE_DEV_RANDOM;
294}
295
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200296void mgmt_fill_version_info(void *ver)
297{
298 struct mgmt_rp_read_version *rp = ver;
299
300 rp->version = MGMT_VERSION;
301 rp->revision = cpu_to_le16(MGMT_REVISION);
302}
303
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300304static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
305 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200306{
307 struct mgmt_rp_read_version rp;
308
Marcel Holtmann181d6952020-05-06 09:57:47 +0200309 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberga38528f2011-01-22 06:46:43 +0200310
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200311 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200312
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200313 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
314 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200315}
316
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300317static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
318 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200319{
320 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200322 size_t rp_size;
323 int i, err;
324
Marcel Holtmann181d6952020-05-06 09:57:47 +0200325 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200326
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700327 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
328 num_commands = ARRAY_SIZE(mgmt_commands);
329 num_events = ARRAY_SIZE(mgmt_events);
330 } else {
331 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
332 num_events = ARRAY_SIZE(mgmt_untrusted_events);
333 }
334
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200335 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
336
337 rp = kmalloc(rp_size, GFP_KERNEL);
338 if (!rp)
339 return -ENOMEM;
340
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700341 rp->num_commands = cpu_to_le16(num_commands);
342 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200343
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700344 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
345 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700347 for (i = 0; i < num_commands; i++, opcode++)
348 put_unaligned_le16(mgmt_commands[i], opcode);
349
350 for (i = 0; i < num_events; i++, opcode++)
351 put_unaligned_le16(mgmt_events[i], opcode);
352 } else {
353 __le16 *opcode = rp->opcodes;
354
355 for (i = 0; i < num_commands; i++, opcode++)
356 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
357
358 for (i = 0; i < num_events; i++, opcode++)
359 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
360 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200361
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200362 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
363 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200364 kfree(rp);
365
366 return err;
367}
368
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300369static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
370 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200371{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200373 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200374 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200375 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300376 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200377
Marcel Holtmann181d6952020-05-06 09:57:47 +0200378 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200379
380 read_lock(&hci_dev_list_lock);
381
382 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300383 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200384 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700385 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700386 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200387 }
388
Johan Hedberga38528f2011-01-22 06:46:43 +0200389 rp_len = sizeof(*rp) + (2 * count);
390 rp = kmalloc(rp_len, GFP_ATOMIC);
391 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100392 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200393 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100394 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200395
Johan Hedberg476e44c2012-10-19 20:10:46 +0300396 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200397 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700398 if (hci_dev_test_flag(d, HCI_SETUP) ||
399 hci_dev_test_flag(d, HCI_CONFIG) ||
400 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200401 continue;
402
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200403 /* Devices marked as raw-only are neither configured
404 * nor unconfigured controllers.
405 */
406 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700407 continue;
408
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200409 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700410 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700411 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200412 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann1514b892013-10-06 08:25:01 -0700413 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200414 }
415
Johan Hedberg476e44c2012-10-19 20:10:46 +0300416 rp->num_controllers = cpu_to_le16(count);
417 rp_len = sizeof(*rp) + (2 * count);
418
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200419 read_unlock(&hci_dev_list_lock);
420
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200421 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
422 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200423
Johan Hedberga38528f2011-01-22 06:46:43 +0200424 kfree(rp);
425
426 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200427}
428
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200429static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
430 void *data, u16 data_len)
431{
432 struct mgmt_rp_read_unconf_index_list *rp;
433 struct hci_dev *d;
434 size_t rp_len;
435 u16 count;
436 int err;
437
Marcel Holtmann181d6952020-05-06 09:57:47 +0200438 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200439
440 read_lock(&hci_dev_list_lock);
441
442 count = 0;
443 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200444 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700445 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200446 count++;
447 }
448
449 rp_len = sizeof(*rp) + (2 * count);
450 rp = kmalloc(rp_len, GFP_ATOMIC);
451 if (!rp) {
452 read_unlock(&hci_dev_list_lock);
453 return -ENOMEM;
454 }
455
456 count = 0;
457 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700458 if (hci_dev_test_flag(d, HCI_SETUP) ||
459 hci_dev_test_flag(d, HCI_CONFIG) ||
460 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200461 continue;
462
463 /* Devices marked as raw-only are neither configured
464 * nor unconfigured controllers.
465 */
466 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
467 continue;
468
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200469 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700470 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200471 rp->index[count++] = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200472 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200473 }
474 }
475
476 rp->num_controllers = cpu_to_le16(count);
477 rp_len = sizeof(*rp) + (2 * count);
478
479 read_unlock(&hci_dev_list_lock);
480
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200481 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
482 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200483
484 kfree(rp);
485
486 return err;
487}
488
Marcel Holtmann96f14742015-03-14 19:27:57 -0700489static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
490 void *data, u16 data_len)
491{
492 struct mgmt_rp_read_ext_index_list *rp;
493 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700494 u16 count;
495 int err;
496
Marcel Holtmann181d6952020-05-06 09:57:47 +0200497 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700498
499 read_lock(&hci_dev_list_lock);
500
501 count = 0;
502 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200503 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700504 count++;
505 }
506
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600507 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700508 if (!rp) {
509 read_unlock(&hci_dev_list_lock);
510 return -ENOMEM;
511 }
512
513 count = 0;
514 list_for_each_entry(d, &hci_dev_list, list) {
515 if (hci_dev_test_flag(d, HCI_SETUP) ||
516 hci_dev_test_flag(d, HCI_CONFIG) ||
517 hci_dev_test_flag(d, HCI_USER_CHANNEL))
518 continue;
519
520 /* Devices marked as raw-only are neither configured
521 * nor unconfigured controllers.
522 */
523 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
524 continue;
525
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200526 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700527 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
528 rp->entry[count].type = 0x01;
529 else
530 rp->entry[count].type = 0x00;
531 } else if (d->dev_type == HCI_AMP) {
532 rp->entry[count].type = 0x02;
533 } else {
534 continue;
535 }
536
537 rp->entry[count].bus = d->bus;
538 rp->entry[count++].index = cpu_to_le16(d->id);
Marcel Holtmann181d6952020-05-06 09:57:47 +0200539 bt_dev_dbg(hdev, "Added hci%u", d->id);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700540 }
541
542 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700543
544 read_unlock(&hci_dev_list_lock);
545
546 /* If this command is called at least once, then all the
547 * default index and unconfigured index events are disabled
548 * and from now on only extended index events are used.
549 */
550 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
551 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
552 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
553
554 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600555 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
556 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700557
558 kfree(rp);
559
560 return err;
561}
562
Marcel Holtmanndbece372014-07-04 18:11:55 +0200563static bool is_configured(struct hci_dev *hdev)
564{
565 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700566 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200567 return false;
568
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800569 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
570 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200571 !bacmp(&hdev->public_addr, BDADDR_ANY))
572 return false;
573
574 return true;
575}
576
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200577static __le32 get_missing_options(struct hci_dev *hdev)
578{
579 u32 options = 0;
580
Marcel Holtmanndbece372014-07-04 18:11:55 +0200581 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700582 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200583 options |= MGMT_OPTION_EXTERNAL_CONFIG;
584
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800585 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
586 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200587 !bacmp(&hdev->public_addr, BDADDR_ANY))
588 options |= MGMT_OPTION_PUBLIC_ADDRESS;
589
590 return cpu_to_le32(options);
591}
592
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200593static int new_options(struct hci_dev *hdev, struct sock *skip)
594{
595 __le32 options = get_missing_options(hdev);
596
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200597 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
598 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200599}
600
Marcel Holtmanndbece372014-07-04 18:11:55 +0200601static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
602{
603 __le32 options = get_missing_options(hdev);
604
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200605 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
606 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200607}
608
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200609static int read_config_info(struct sock *sk, struct hci_dev *hdev,
610 void *data, u16 data_len)
611{
612 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200613 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200614
Marcel Holtmann181d6952020-05-06 09:57:47 +0200615 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200616
617 hci_dev_lock(hdev);
618
619 memset(&rp, 0, sizeof(rp));
620 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200621
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200622 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
623 options |= MGMT_OPTION_EXTERNAL_CONFIG;
624
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200625 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200626 options |= MGMT_OPTION_PUBLIC_ADDRESS;
627
628 rp.supported_options = cpu_to_le32(options);
629 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200630
631 hci_dev_unlock(hdev);
632
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200633 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
634 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200635}
636
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530637static u32 get_supported_phys(struct hci_dev *hdev)
638{
639 u32 supported_phys = 0;
640
641 if (lmp_bredr_capable(hdev)) {
642 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
643
644 if (hdev->features[0][0] & LMP_3SLOT)
645 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
646
647 if (hdev->features[0][0] & LMP_5SLOT)
648 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
649
650 if (lmp_edr_2m_capable(hdev)) {
651 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
652
653 if (lmp_edr_3slot_capable(hdev))
654 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
655
656 if (lmp_edr_5slot_capable(hdev))
657 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
658
659 if (lmp_edr_3m_capable(hdev)) {
660 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
661
662 if (lmp_edr_3slot_capable(hdev))
663 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
664
665 if (lmp_edr_5slot_capable(hdev))
666 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
667 }
668 }
669 }
670
671 if (lmp_le_capable(hdev)) {
672 supported_phys |= MGMT_PHY_LE_1M_TX;
673 supported_phys |= MGMT_PHY_LE_1M_RX;
674
675 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
676 supported_phys |= MGMT_PHY_LE_2M_TX;
677 supported_phys |= MGMT_PHY_LE_2M_RX;
678 }
679
680 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
681 supported_phys |= MGMT_PHY_LE_CODED_TX;
682 supported_phys |= MGMT_PHY_LE_CODED_RX;
683 }
684 }
685
686 return supported_phys;
687}
688
689static u32 get_selected_phys(struct hci_dev *hdev)
690{
691 u32 selected_phys = 0;
692
693 if (lmp_bredr_capable(hdev)) {
694 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
695
696 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
697 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
698
699 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
700 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
701
702 if (lmp_edr_2m_capable(hdev)) {
703 if (!(hdev->pkt_type & HCI_2DH1))
704 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
705
706 if (lmp_edr_3slot_capable(hdev) &&
707 !(hdev->pkt_type & HCI_2DH3))
708 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
709
710 if (lmp_edr_5slot_capable(hdev) &&
711 !(hdev->pkt_type & HCI_2DH5))
712 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
713
714 if (lmp_edr_3m_capable(hdev)) {
715 if (!(hdev->pkt_type & HCI_3DH1))
716 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
717
718 if (lmp_edr_3slot_capable(hdev) &&
719 !(hdev->pkt_type & HCI_3DH3))
720 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
721
722 if (lmp_edr_5slot_capable(hdev) &&
723 !(hdev->pkt_type & HCI_3DH5))
724 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
725 }
726 }
727 }
728
729 if (lmp_le_capable(hdev)) {
730 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
731 selected_phys |= MGMT_PHY_LE_1M_TX;
732
733 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
734 selected_phys |= MGMT_PHY_LE_1M_RX;
735
736 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
737 selected_phys |= MGMT_PHY_LE_2M_TX;
738
739 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
740 selected_phys |= MGMT_PHY_LE_2M_RX;
741
742 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
743 selected_phys |= MGMT_PHY_LE_CODED_TX;
744
745 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
746 selected_phys |= MGMT_PHY_LE_CODED_RX;
747 }
748
749 return selected_phys;
750}
751
752static u32 get_configurable_phys(struct hci_dev *hdev)
753{
754 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
755 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
756}
757
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200758static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200759{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200760 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200761
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200762 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300763 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800764 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300765 settings |= MGMT_SETTING_CONNECTABLE;
766 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200767
Andre Guedesed3fa312012-07-24 15:03:46 -0300768 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500769 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
770 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 settings |= MGMT_SETTING_BREDR;
772 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700773
774 if (lmp_ssp_capable(hdev)) {
775 settings |= MGMT_SETTING_SSP;
776 settings |= MGMT_SETTING_HS;
777 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800778
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800779 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800780 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000781
Alain Michaud00bce3f2020-03-05 16:14:59 +0000782 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000783 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000784 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700785 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100786
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300787 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200788 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300789 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300790 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200791 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800792 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300793 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200794
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200795 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
796 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200797 settings |= MGMT_SETTING_CONFIGURATION;
798
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530799 settings |= MGMT_SETTING_PHY_CONFIGURATION;
800
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200801 return settings;
802}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200803
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200804static u32 get_current_settings(struct hci_dev *hdev)
805{
806 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200807
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200808 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100809 settings |= MGMT_SETTING_POWERED;
810
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700811 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200812 settings |= MGMT_SETTING_CONNECTABLE;
813
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700814 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500815 settings |= MGMT_SETTING_FAST_CONNECTABLE;
816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700817 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200818 settings |= MGMT_SETTING_DISCOVERABLE;
819
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700820 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300821 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700823 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200824 settings |= MGMT_SETTING_BREDR;
825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700826 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700829 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200830 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200831
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700832 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200834
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700835 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200836 settings |= MGMT_SETTING_HS;
837
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700838 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300839 settings |= MGMT_SETTING_ADVERTISING;
840
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700841 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800842 settings |= MGMT_SETTING_SECURE_CONN;
843
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700844 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800845 settings |= MGMT_SETTING_DEBUG_KEYS;
846
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700847 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200848 settings |= MGMT_SETTING_PRIVACY;
849
Marcel Holtmann93690c22015-03-06 10:11:21 -0800850 /* The current setting for static address has two purposes. The
851 * first is to indicate if the static address will be used and
852 * the second is to indicate if it is actually set.
853 *
854 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700855 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800856 * address is actually used decides if the flag is set or not.
857 *
858 * For single mode LE only controllers and dual-mode controllers
859 * with BR/EDR disabled, the existence of the static address will
860 * be evaluated.
861 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700862 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700863 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800864 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
865 if (bacmp(&hdev->static_addr, BDADDR_ANY))
866 settings |= MGMT_SETTING_STATIC_ADDRESS;
867 }
868
Alain Michaud00bce3f2020-03-05 16:14:59 +0000869 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
870 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
871
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200873}
874
Johan Hedberg333ae952015-03-17 13:48:47 +0200875static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
876{
877 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
878}
879
Johan Hedberg333ae952015-03-17 13:48:47 +0200880static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
881 struct hci_dev *hdev,
882 const void *data)
883{
884 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
885}
886
Johan Hedbergf2252572015-11-18 12:49:20 +0200887u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300888{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200889 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300890
891 /* If there's a pending mgmt command the flags will not yet have
892 * their final values, so check for this first.
893 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200894 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300895 if (cmd) {
896 struct mgmt_mode *cp = cmd->param;
897 if (cp->val == 0x01)
898 return LE_AD_GENERAL;
899 else if (cp->val == 0x02)
900 return LE_AD_LIMITED;
901 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700902 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300903 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700904 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300905 return LE_AD_GENERAL;
906 }
907
908 return 0;
909}
910
Johan Hedbergf2252572015-11-18 12:49:20 +0200911bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700912{
913 struct mgmt_pending_cmd *cmd;
914
915 /* If there's a pending mgmt command the flag will not yet have
916 * it's final value, so check for this first.
917 */
918 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
919 if (cmd) {
920 struct mgmt_mode *cp = cmd->param;
921
922 return cp->val;
923 }
924
925 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
926}
927
Johan Hedberg7d785252011-12-15 00:47:39 +0200928static void service_cache_off(struct work_struct *work)
929{
930 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300931 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500932 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200933
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700934 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200935 return;
936
Johan Hedberg890ea892013-03-15 17:06:52 -0500937 hci_req_init(&req, hdev);
938
Johan Hedberg7d785252011-12-15 00:47:39 +0200939 hci_dev_lock(hdev);
940
Johan Hedbergb1a89172015-11-25 16:15:42 +0200941 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200942 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200943
944 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500945
946 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200947}
948
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200949static void rpa_expired(struct work_struct *work)
950{
951 struct hci_dev *hdev = container_of(work, struct hci_dev,
952 rpa_expired.work);
953 struct hci_request req;
954
Marcel Holtmann181d6952020-05-06 09:57:47 +0200955 bt_dev_dbg(hdev, "");
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200956
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700957 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200958
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700959 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200960 return;
961
962 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200963 * controller happens in the hci_req_enable_advertising()
964 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200965 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200966 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530967 if (ext_adv_capable(hdev))
968 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
969 else
970 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200971 hci_req_run(&req, NULL);
972}
973
Johan Hedberg6a919082012-02-28 06:17:26 +0200974static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200975{
Marcel Holtmann238be782015-03-13 02:11:06 -0700976 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200977 return;
978
Johan Hedberg4f87da82012-03-02 19:55:56 +0200979 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200980 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200981
Johan Hedberg4f87da82012-03-02 19:55:56 +0200982 /* Non-mgmt controlled devices get this bit set
983 * implicitly so that pairing works for them, however
984 * for mgmt we require user-space to explicitly enable
985 * it
986 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700987 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200988}
989
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200990static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300991 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200992{
993 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200994
Marcel Holtmann181d6952020-05-06 09:57:47 +0200995 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg03811012010-12-08 00:21:06 +0200996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200998
Johan Hedberg03811012010-12-08 00:21:06 +0200999 memset(&rp, 0, sizeof(rp));
1000
Johan Hedberg03811012010-12-08 00:21:06 +02001001 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001002
1003 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001004 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001005
1006 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1007 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1008
1009 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001010
1011 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001012 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001014 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001015
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001016 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1017 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001018}
1019
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001020static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1021{
1022 u16 eir_len = 0;
1023 size_t name_len;
1024
1025 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1026 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1027 hdev->dev_class, 3);
1028
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001029 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1030 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1031 hdev->appearance);
1032
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001033 name_len = strlen(hdev->dev_name);
1034 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1035 hdev->dev_name, name_len);
1036
1037 name_len = strlen(hdev->short_name);
1038 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1039 hdev->short_name, name_len);
1040
1041 return eir_len;
1042}
1043
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001044static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1045 void *data, u16 data_len)
1046{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001047 char buf[512];
1048 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001049 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001050
Marcel Holtmann181d6952020-05-06 09:57:47 +02001051 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001052
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001053 memset(&buf, 0, sizeof(buf));
1054
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001055 hci_dev_lock(hdev);
1056
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001057 bacpy(&rp->bdaddr, &hdev->bdaddr);
1058
1059 rp->version = hdev->hci_ver;
1060 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1061
1062 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1063 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001064
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001065
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001066 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001067 rp->eir_len = cpu_to_le16(eir_len);
1068
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001069 hci_dev_unlock(hdev);
1070
1071 /* If this command is called at least once, then the events
1072 * for class of device and local name changes are disabled
1073 * and only the new extended controller information event
1074 * is used.
1075 */
1076 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1077 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1078 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1079
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001080 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1081 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001082}
1083
1084static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1085{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001086 char buf[512];
1087 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1088 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001089
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001090 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001091
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001092 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1093 ev->eir_len = cpu_to_le16(eir_len);
1094
1095 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1096 sizeof(*ev) + eir_len,
1097 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001098}
1099
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001100static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001101{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001102 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001103
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001104 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1105 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001106}
1107
Marcel Holtmann1904a852015-01-11 13:50:44 -08001108static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001109{
Marcel Holtmann181d6952020-05-06 09:57:47 +02001110 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001111
Johan Hedberga3172b72014-02-28 09:33:44 +02001112 if (hci_conn_count(hdev) == 0) {
1113 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001114 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001115 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001116}
1117
Johan Hedbergf2252572015-11-18 12:49:20 +02001118void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001119{
1120 struct mgmt_ev_advertising_added ev;
1121
1122 ev.instance = instance;
1123
1124 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1125}
1126
Johan Hedbergf2252572015-11-18 12:49:20 +02001127void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1128 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001129{
1130 struct mgmt_ev_advertising_removed ev;
1131
1132 ev.instance = instance;
1133
1134 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1135}
1136
Florian Grandel7816b822015-06-18 03:16:45 +02001137static void cancel_adv_timeout(struct hci_dev *hdev)
1138{
1139 if (hdev->adv_instance_timeout) {
1140 hdev->adv_instance_timeout = 0;
1141 cancel_delayed_work(&hdev->adv_instance_expire);
1142 }
1143}
1144
Johan Hedberg8b064a32014-02-24 14:52:22 +02001145static int clean_up_hci_state(struct hci_dev *hdev)
1146{
1147 struct hci_request req;
1148 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001149 bool discov_stopped;
1150 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001151
1152 hci_req_init(&req, hdev);
1153
1154 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1155 test_bit(HCI_PSCAN, &hdev->flags)) {
1156 u8 scan = 0x00;
1157 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1158 }
1159
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001160 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001161
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001162 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001163 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001164
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001165 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001166
1167 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001168 /* 0x15 == Terminated due to Power Off */
1169 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001170 }
1171
Johan Hedberg23a48092014-07-08 16:05:06 +03001172 err = hci_req_run(&req, clean_up_hci_complete);
1173 if (!err && discov_stopped)
1174 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1175
1176 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001177}
1178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001180 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001182 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001183 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001184 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185
Marcel Holtmann181d6952020-05-06 09:57:47 +02001186 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187
Johan Hedberga7e80f22013-01-09 16:05:19 +02001188 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001189 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1190 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001191
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001192 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
Johan Hedberg333ae952015-03-17 13:48:47 +02001194 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001195 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1196 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001197 goto failed;
1198 }
1199
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001200 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001201 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202 goto failed;
1203 }
1204
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1206 if (!cmd) {
1207 err = -ENOMEM;
1208 goto failed;
1209 }
1210
Johan Hedberg8b064a32014-02-24 14:52:22 +02001211 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001212 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001213 err = 0;
1214 } else {
1215 /* Disconnect connections, stop scans, etc */
1216 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001217 if (!err)
1218 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1219 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220
Johan Hedberg8b064a32014-02-24 14:52:22 +02001221 /* ENODATA means there were no HCI commands queued */
1222 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001223 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001224 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1225 err = 0;
1226 }
1227 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001228
1229failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001230 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001231 return err;
1232}
1233
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001234static int new_settings(struct hci_dev *hdev, struct sock *skip)
1235{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001236 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001237
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001238 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1239 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001240}
1241
Johan Hedberg91a668b2014-07-09 13:28:26 +03001242int mgmt_new_settings(struct hci_dev *hdev)
1243{
1244 return new_settings(hdev, NULL);
1245}
1246
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001247struct cmd_lookup {
1248 struct sock *sk;
1249 struct hci_dev *hdev;
1250 u8 mgmt_status;
1251};
1252
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001253static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001254{
1255 struct cmd_lookup *match = data;
1256
1257 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1258
1259 list_del(&cmd->list);
1260
1261 if (match->sk == NULL) {
1262 match->sk = cmd->sk;
1263 sock_hold(match->sk);
1264 }
1265
1266 mgmt_pending_free(cmd);
1267}
1268
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001269static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001270{
1271 u8 *status = data;
1272
Johan Hedberga69e8372015-03-06 21:08:53 +02001273 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001274 mgmt_pending_remove(cmd);
1275}
1276
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001277static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001278{
1279 if (cmd->cmd_complete) {
1280 u8 *status = data;
1281
1282 cmd->cmd_complete(cmd, *status);
1283 mgmt_pending_remove(cmd);
1284
1285 return;
1286 }
1287
1288 cmd_status_rsp(cmd, data);
1289}
1290
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001291static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001292{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001293 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1294 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001295}
1296
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001297static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001298{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001299 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1300 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001301}
1302
Johan Hedberge6fe7982013-10-02 15:45:22 +03001303static u8 mgmt_bredr_support(struct hci_dev *hdev)
1304{
1305 if (!lmp_bredr_capable(hdev))
1306 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001307 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001308 return MGMT_STATUS_REJECTED;
1309 else
1310 return MGMT_STATUS_SUCCESS;
1311}
1312
1313static u8 mgmt_le_support(struct hci_dev *hdev)
1314{
1315 if (!lmp_le_capable(hdev))
1316 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001317 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001318 return MGMT_STATUS_REJECTED;
1319 else
1320 return MGMT_STATUS_SUCCESS;
1321}
1322
Johan Hedbergaed1a882015-11-22 17:24:44 +03001323void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001324{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001325 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001326
Marcel Holtmann181d6952020-05-06 09:57:47 +02001327 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001328
1329 hci_dev_lock(hdev);
1330
Johan Hedberg333ae952015-03-17 13:48:47 +02001331 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001332 if (!cmd)
1333 goto unlock;
1334
1335 if (status) {
1336 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001337 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001338 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001339 goto remove_cmd;
1340 }
1341
Johan Hedbergaed1a882015-11-22 17:24:44 +03001342 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1343 hdev->discov_timeout > 0) {
1344 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1345 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001346 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001347
1348 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001349 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001350
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001351remove_cmd:
1352 mgmt_pending_remove(cmd);
1353
1354unlock:
1355 hci_dev_unlock(hdev);
1356}
1357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001358static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001359 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001360{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001361 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001362 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001363 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001364 int err;
1365
Marcel Holtmann181d6952020-05-06 09:57:47 +02001366 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001367
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001368 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1369 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001370 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1371 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001372
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001373 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001374 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1375 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001376
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001377 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001378
1379 /* Disabling discoverable requires that no timeout is set,
1380 * and enabling limited discoverable requires a timeout.
1381 */
1382 if ((cp->val == 0x00 && timeout > 0) ||
1383 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001384 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1385 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001386
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001387 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001388
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001389 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001390 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1391 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001392 goto failed;
1393 }
1394
Johan Hedberg333ae952015-03-17 13:48:47 +02001395 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1396 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001397 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1398 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001399 goto failed;
1400 }
1401
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001402 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001403 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1404 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001405 goto failed;
1406 }
1407
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001408 if (hdev->advertising_paused) {
1409 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1410 MGMT_STATUS_BUSY);
1411 goto failed;
1412 }
1413
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001414 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001415 bool changed = false;
1416
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001417 /* Setting limited discoverable when powered off is
1418 * not a valid operation since it requires a timeout
1419 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1420 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001421 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001422 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001423 changed = true;
1424 }
1425
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001426 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001427 if (err < 0)
1428 goto failed;
1429
1430 if (changed)
1431 err = new_settings(hdev, sk);
1432
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001433 goto failed;
1434 }
1435
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001436 /* If the current mode is the same, then just update the timeout
1437 * value with the new value. And if only the timeout gets updated,
1438 * then no need for any HCI transactions.
1439 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001440 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1441 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1442 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001443 cancel_delayed_work(&hdev->discov_off);
1444 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001445
Marcel Holtmann36261542013-10-15 08:28:51 -07001446 if (cp->val && hdev->discov_timeout > 0) {
1447 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001448 queue_delayed_work(hdev->req_workqueue,
1449 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001450 }
1451
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001452 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001453 goto failed;
1454 }
1455
1456 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1457 if (!cmd) {
1458 err = -ENOMEM;
1459 goto failed;
1460 }
1461
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001462 /* Cancel any potential discoverable timeout that might be
1463 * still active and store new timeout value. The arming of
1464 * the timeout happens in the complete handler.
1465 */
1466 cancel_delayed_work(&hdev->discov_off);
1467 hdev->discov_timeout = timeout;
1468
Johan Hedbergaed1a882015-11-22 17:24:44 +03001469 if (cp->val)
1470 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1471 else
1472 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1473
Johan Hedbergb456f872013-10-19 23:38:22 +03001474 /* Limited discoverable mode */
1475 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001476 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001477 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001478 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001479
Johan Hedbergaed1a882015-11-22 17:24:44 +03001480 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1481 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001483failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001485 return err;
1486}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001487
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001488void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001489{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001490 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001491
Marcel Holtmann181d6952020-05-06 09:57:47 +02001492 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001493
1494 hci_dev_lock(hdev);
1495
Johan Hedberg333ae952015-03-17 13:48:47 +02001496 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001497 if (!cmd)
1498 goto unlock;
1499
Johan Hedberg37438c12013-10-14 16:20:05 +03001500 if (status) {
1501 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001502 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001503 goto remove_cmd;
1504 }
1505
Johan Hedberg2b76f452013-03-15 17:07:04 -05001506 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001507 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001508
Johan Hedberg37438c12013-10-14 16:20:05 +03001509remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001510 mgmt_pending_remove(cmd);
1511
1512unlock:
1513 hci_dev_unlock(hdev);
1514}
1515
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001516static int set_connectable_update_settings(struct hci_dev *hdev,
1517 struct sock *sk, u8 val)
1518{
1519 bool changed = false;
1520 int err;
1521
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001522 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001523 changed = true;
1524
1525 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001526 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001527 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001528 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1529 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001530 }
1531
1532 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1533 if (err < 0)
1534 return err;
1535
Johan Hedberg562064e2014-07-08 16:35:34 +03001536 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001537 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001538 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001539 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001540 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001541
1542 return 0;
1543}
1544
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001545static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001546 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001547{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001548 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001549 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001550 int err;
1551
Marcel Holtmann181d6952020-05-06 09:57:47 +02001552 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001554 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1555 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1557 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001558
Johan Hedberga7e80f22013-01-09 16:05:19 +02001559 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001560 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1561 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001562
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001563 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001564
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001565 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001566 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001567 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001568 }
1569
Johan Hedberg333ae952015-03-17 13:48:47 +02001570 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1571 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001572 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1573 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001574 goto failed;
1575 }
1576
Johan Hedberg73f22f62010-12-29 16:00:25 +02001577 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1578 if (!cmd) {
1579 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001580 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001581 }
1582
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001583 if (cp->val) {
1584 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1585 } else {
1586 if (hdev->discov_timeout > 0)
1587 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001588
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001589 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1590 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1591 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001592 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001593
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001594 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1595 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001596
1597failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001598 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001599 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001600}
1601
Johan Hedbergb2939472014-07-30 09:22:23 +03001602static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001604{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001605 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001606 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001607 int err;
1608
Marcel Holtmann181d6952020-05-06 09:57:47 +02001609 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001610
Johan Hedberga7e80f22013-01-09 16:05:19 +02001611 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001612 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1613 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001614
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001615 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001616
1617 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001618 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001619 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001620 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001621
Johan Hedbergb2939472014-07-30 09:22:23 +03001622 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001623 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001624 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001625
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001626 if (changed) {
1627 /* In limited privacy mode the change of bondable mode
1628 * may affect the local advertising address.
1629 */
1630 if (hdev_is_powered(hdev) &&
1631 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1632 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1633 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1634 queue_work(hdev->req_workqueue,
1635 &hdev->discoverable_update);
1636
Marcel Holtmann55594352013-10-06 16:11:57 -07001637 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001638 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001639
Marcel Holtmann55594352013-10-06 16:11:57 -07001640unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001641 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001642 return err;
1643}
1644
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001645static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1646 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001647{
1648 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001649 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001650 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001651 int err;
1652
Marcel Holtmann181d6952020-05-06 09:57:47 +02001653 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001654
Johan Hedberge6fe7982013-10-02 15:45:22 +03001655 status = mgmt_bredr_support(hdev);
1656 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001657 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1658 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001659
Johan Hedberga7e80f22013-01-09 16:05:19 +02001660 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001661 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1662 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001663
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001664 hci_dev_lock(hdev);
1665
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001666 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001667 bool changed = false;
1668
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001669 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001670 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001671 changed = true;
1672 }
1673
1674 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1675 if (err < 0)
1676 goto failed;
1677
1678 if (changed)
1679 err = new_settings(hdev, sk);
1680
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001681 goto failed;
1682 }
1683
Johan Hedberg333ae952015-03-17 13:48:47 +02001684 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001685 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1686 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001687 goto failed;
1688 }
1689
1690 val = !!cp->val;
1691
1692 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1693 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1694 goto failed;
1695 }
1696
1697 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1698 if (!cmd) {
1699 err = -ENOMEM;
1700 goto failed;
1701 }
1702
1703 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1704 if (err < 0) {
1705 mgmt_pending_remove(cmd);
1706 goto failed;
1707 }
1708
1709failed:
1710 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001711 return err;
1712}
1713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001715{
1716 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001717 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001718 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001719 int err;
1720
Marcel Holtmann181d6952020-05-06 09:57:47 +02001721 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001722
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001723 status = mgmt_bredr_support(hdev);
1724 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001725 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001726
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001727 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001728 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1729 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001730
Johan Hedberga7e80f22013-01-09 16:05:19 +02001731 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001732 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1733 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001734
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001735 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001736
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001737 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001738 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001739
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001740 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001741 changed = !hci_dev_test_and_set_flag(hdev,
1742 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001743 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001744 changed = hci_dev_test_and_clear_flag(hdev,
1745 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001746 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001747 changed = hci_dev_test_and_clear_flag(hdev,
1748 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001749 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001750 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001751 }
1752
1753 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1754 if (err < 0)
1755 goto failed;
1756
1757 if (changed)
1758 err = new_settings(hdev, sk);
1759
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001760 goto failed;
1761 }
1762
Johan Hedberg333ae952015-03-17 13:48:47 +02001763 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001764 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1765 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001766 goto failed;
1767 }
1768
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001769 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001770 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1771 goto failed;
1772 }
1773
1774 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1775 if (!cmd) {
1776 err = -ENOMEM;
1777 goto failed;
1778 }
1779
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001780 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001781 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1782 sizeof(cp->val), &cp->val);
1783
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001784 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001785 if (err < 0) {
1786 mgmt_pending_remove(cmd);
1787 goto failed;
1788 }
1789
1790failed:
1791 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001792 return err;
1793}
1794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001795static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001796{
1797 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001798 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001799 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001800 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001801
Marcel Holtmann181d6952020-05-06 09:57:47 +02001802 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001803
Johan Hedberge6fe7982013-10-02 15:45:22 +03001804 status = mgmt_bredr_support(hdev);
1805 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001806 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001807
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001808 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001809 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1810 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001811
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001812 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001813 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1814 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001815
Johan Hedberga7e80f22013-01-09 16:05:19 +02001816 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001817 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1818 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001819
Marcel Holtmannee392692013-10-01 22:59:23 -07001820 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001821
Johan Hedberg333ae952015-03-17 13:48:47 +02001822 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001823 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1824 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001825 goto unlock;
1826 }
1827
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001828 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001829 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001830 } else {
1831 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001832 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1833 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001834 goto unlock;
1835 }
1836
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001837 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001838 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001839
1840 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1841 if (err < 0)
1842 goto unlock;
1843
1844 if (changed)
1845 err = new_settings(hdev, sk);
1846
1847unlock:
1848 hci_dev_unlock(hdev);
1849 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001850}
1851
Marcel Holtmann1904a852015-01-11 13:50:44 -08001852static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001853{
1854 struct cmd_lookup match = { NULL, hdev };
1855
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301856 hci_dev_lock(hdev);
1857
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001858 if (status) {
1859 u8 mgmt_err = mgmt_status(status);
1860
1861 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1862 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301863 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001864 }
1865
1866 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1867
1868 new_settings(hdev, match.sk);
1869
1870 if (match.sk)
1871 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001872
1873 /* Make sure the controller has a good default for
1874 * advertising data. Restrict the update to when LE
1875 * has actually been enabled. During power on, the
1876 * update in powered_update_hci will take care of it.
1877 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001878 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001879 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001880 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301881 if (ext_adv_capable(hdev)) {
1882 int err;
1883
1884 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1885 if (!err)
1886 __hci_req_update_scan_rsp_data(&req, 0x00);
1887 } else {
1888 __hci_req_update_adv_data(&req, 0x00);
1889 __hci_req_update_scan_rsp_data(&req, 0x00);
1890 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001891 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001892 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001893 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301894
1895unlock:
1896 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001897}
1898
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001899static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001900{
1901 struct mgmt_mode *cp = data;
1902 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001903 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001904 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001905 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001906 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001907
Marcel Holtmann181d6952020-05-06 09:57:47 +02001908 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001910 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001911 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1912 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001913
Johan Hedberga7e80f22013-01-09 16:05:19 +02001914 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001915 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1916 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001917
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001918 /* Bluetooth single mode LE only controllers or dual-mode
1919 * controllers configured as LE only devices, do not allow
1920 * switching LE off. These have either LE enabled explicitly
1921 * or BR/EDR has been previously switched off.
1922 *
1923 * When trying to enable an already enabled LE, then gracefully
1924 * send a positive response. Trying to disable it however will
1925 * result into rejection.
1926 */
1927 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1928 if (cp->val == 0x01)
1929 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1930
Johan Hedberga69e8372015-03-06 21:08:53 +02001931 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1932 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001933 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001934
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001935 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001936
1937 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001938 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001939
Florian Grandel847818d2015-06-18 03:16:46 +02001940 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001941 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001942
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001943 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944 bool changed = false;
1945
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001946 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001947 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001948 changed = true;
1949 }
1950
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001951 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001952 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001953 changed = true;
1954 }
1955
Johan Hedberg06199cf2012-02-22 16:37:11 +02001956 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1957 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001958 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001959
1960 if (changed)
1961 err = new_settings(hdev, sk);
1962
Johan Hedberg1de028c2012-02-29 19:55:35 -08001963 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001964 }
1965
Johan Hedberg333ae952015-03-17 13:48:47 +02001966 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1967 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001968 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1969 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001970 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001971 }
1972
1973 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1974 if (!cmd) {
1975 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001976 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001977 }
1978
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001979 hci_req_init(&req, hdev);
1980
Johan Hedberg06199cf2012-02-22 16:37:11 +02001981 memset(&hci_cp, 0, sizeof(hci_cp));
1982
1983 if (val) {
1984 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001985 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001986 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001987 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001988 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301989
1990 if (ext_adv_capable(hdev))
1991 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001992 }
1993
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001994 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1995 &hci_cp);
1996
1997 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301998 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001999 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002000
Johan Hedberg1de028c2012-02-29 19:55:35 -08002001unlock:
2002 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002003 return err;
2004}
2005
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002006/* This is a helper function to test for pending mgmt commands that can
2007 * cause CoD or EIR HCI commands. We can only allow one such pending
2008 * mgmt command at a time since otherwise we cannot easily track what
2009 * the current values are, will be, and based on that calculate if a new
2010 * HCI command needs to be sent and if yes with what value.
2011 */
2012static bool pending_eir_or_class(struct hci_dev *hdev)
2013{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002014 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002015
2016 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2017 switch (cmd->opcode) {
2018 case MGMT_OP_ADD_UUID:
2019 case MGMT_OP_REMOVE_UUID:
2020 case MGMT_OP_SET_DEV_CLASS:
2021 case MGMT_OP_SET_POWERED:
2022 return true;
2023 }
2024 }
2025
2026 return false;
2027}
2028
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002029static const u8 bluetooth_base_uuid[] = {
2030 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2031 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2032};
2033
2034static u8 get_uuid_size(const u8 *uuid)
2035{
2036 u32 val;
2037
2038 if (memcmp(uuid, bluetooth_base_uuid, 12))
2039 return 128;
2040
2041 val = get_unaligned_le32(&uuid[12]);
2042 if (val > 0xffff)
2043 return 32;
2044
2045 return 16;
2046}
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2049{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002050 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002051
2052 hci_dev_lock(hdev);
2053
Johan Hedberg333ae952015-03-17 13:48:47 +02002054 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002055 if (!cmd)
2056 goto unlock;
2057
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002058 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2059 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002060
2061 mgmt_pending_remove(cmd);
2062
2063unlock:
2064 hci_dev_unlock(hdev);
2065}
2066
Marcel Holtmann1904a852015-01-11 13:50:44 -08002067static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002068{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002069 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002070
2071 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2072}
2073
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002074static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002075{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002076 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002077 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002078 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002079 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002080 int err;
2081
Marcel Holtmann181d6952020-05-06 09:57:47 +02002082 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002083
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002084 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002086 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002087 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2088 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002089 goto failed;
2090 }
2091
Andre Guedes92c4c202012-06-07 19:05:44 -03002092 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002093 if (!uuid) {
2094 err = -ENOMEM;
2095 goto failed;
2096 }
2097
2098 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002099 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002100 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002101
Johan Hedbergde66aa62013-01-27 00:31:27 +02002102 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002103
Johan Hedberg890ea892013-03-15 17:06:52 -05002104 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002105
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002106 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002107 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002108
Johan Hedberg92da6092013-03-15 17:06:55 -05002109 err = hci_req_run(&req, add_uuid_complete);
2110 if (err < 0) {
2111 if (err != -ENODATA)
2112 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002113
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002114 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2115 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002116 goto failed;
2117 }
2118
2119 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002120 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002121 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002122 goto failed;
2123 }
2124
2125 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002126
2127failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002128 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 return err;
2130}
2131
Johan Hedberg24b78d02012-02-23 23:24:30 +02002132static bool enable_service_cache(struct hci_dev *hdev)
2133{
2134 if (!hdev_is_powered(hdev))
2135 return false;
2136
Marcel Holtmann238be782015-03-13 02:11:06 -07002137 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002138 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2139 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002140 return true;
2141 }
2142
2143 return false;
2144}
2145
Marcel Holtmann1904a852015-01-11 13:50:44 -08002146static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002147{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002148 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002149
2150 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2151}
2152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002154 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002155{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002156 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002157 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002158 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159 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 -05002160 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002161 int err, found;
2162
Marcel Holtmann181d6952020-05-06 09:57:47 +02002163 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002165 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002166
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002167 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2169 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002170 goto unlock;
2171 }
2172
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002173 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002174 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002175
Johan Hedberg24b78d02012-02-23 23:24:30 +02002176 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002177 err = mgmt_cmd_complete(sk, hdev->id,
2178 MGMT_OP_REMOVE_UUID,
2179 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002180 goto unlock;
2181 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002182
Johan Hedberg9246a862012-02-23 21:33:16 +02002183 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002184 }
2185
2186 found = 0;
2187
Johan Hedberg056341c2013-01-27 00:31:30 +02002188 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2190 continue;
2191
2192 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002193 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002194 found++;
2195 }
2196
2197 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002198 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2199 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002200 goto unlock;
2201 }
2202
Johan Hedberg9246a862012-02-23 21:33:16 +02002203update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002204 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002205
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002206 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002207 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002208
Johan Hedberg92da6092013-03-15 17:06:55 -05002209 err = hci_req_run(&req, remove_uuid_complete);
2210 if (err < 0) {
2211 if (err != -ENODATA)
2212 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002213
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002214 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2215 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002216 goto unlock;
2217 }
2218
2219 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002220 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002221 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002222 goto unlock;
2223 }
2224
2225 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002226
2227unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002229 return err;
2230}
2231
Marcel Holtmann1904a852015-01-11 13:50:44 -08002232static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002233{
Marcel Holtmann181d6952020-05-06 09:57:47 +02002234 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg92da6092013-03-15 17:06:55 -05002235
2236 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2237}
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002240 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002242 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002243 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002244 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002245 int err;
2246
Marcel Holtmann181d6952020-05-06 09:57:47 +02002247 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002248
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002249 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002250 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2251 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002253 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002254
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002255 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002256 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2257 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002258 goto unlock;
2259 }
2260
2261 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002262 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2263 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002264 goto unlock;
2265 }
2266
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002267 hdev->major_class = cp->major;
2268 hdev->minor_class = cp->minor;
2269
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002270 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002271 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2272 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002273 goto unlock;
2274 }
2275
Johan Hedberg890ea892013-03-15 17:06:52 -05002276 hci_req_init(&req, hdev);
2277
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002278 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002279 hci_dev_unlock(hdev);
2280 cancel_delayed_work_sync(&hdev->service_cache);
2281 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002282 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002283 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002284
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002285 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002286
Johan Hedberg92da6092013-03-15 17:06:55 -05002287 err = hci_req_run(&req, set_class_complete);
2288 if (err < 0) {
2289 if (err != -ENODATA)
2290 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002291
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002292 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2293 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002294 goto unlock;
2295 }
2296
2297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002298 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002299 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002300 goto unlock;
2301 }
2302
2303 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002304
Johan Hedbergb5235a62012-02-21 14:32:24 +02002305unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002306 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002307 return err;
2308}
2309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002310static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002311 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002312{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002313 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002314 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2315 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002316 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002317 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002318 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319
Marcel Holtmann181d6952020-05-06 09:57:47 +02002320 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002321
2322 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002323 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2324 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002325
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002326 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002327 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002328 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2329 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002330 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2331 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002332 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002334 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002335 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002336 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2337 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002338 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2339 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340 }
2341
Johan Hedberg4ae143012013-01-20 14:27:13 +02002342 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002343 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2344 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002345
Marcel Holtmann181d6952020-05-06 09:57:47 +02002346 bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys,
2347 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002348
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002349 for (i = 0; i < key_count; i++) {
2350 struct mgmt_link_key_info *key = &cp->keys[i];
2351
Marcel Holtmann8e991132014-01-10 02:07:25 -08002352 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002353 return mgmt_cmd_status(sk, hdev->id,
2354 MGMT_OP_LOAD_LINK_KEYS,
2355 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002356 }
2357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002358 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359
2360 hci_link_keys_clear(hdev);
2361
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002362 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002363 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002365 changed = hci_dev_test_and_clear_flag(hdev,
2366 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002367
2368 if (changed)
2369 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002370
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002371 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002372 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373
Alain Michaud600a8742020-01-07 00:43:17 +00002374 if (hci_is_blocked_key(hdev,
2375 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2376 key->val)) {
2377 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2378 &key->addr.bdaddr);
2379 continue;
2380 }
2381
Johan Hedberg58e92932014-06-24 14:00:26 +03002382 /* Always ignore debug keys and require a new pairing if
2383 * the user wants to use them.
2384 */
2385 if (key->type == HCI_LK_DEBUG_COMBINATION)
2386 continue;
2387
Johan Hedberg7652ff62014-06-24 13:15:49 +03002388 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2389 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002390 }
2391
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002392 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002394 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002395
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002396 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002397}
2398
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002399static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002400 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002401{
2402 struct mgmt_ev_device_unpaired ev;
2403
2404 bacpy(&ev.addr.bdaddr, bdaddr);
2405 ev.addr.type = addr_type;
2406
2407 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002408 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002409}
2410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002411static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002413{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002414 struct mgmt_cp_unpair_device *cp = data;
2415 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002416 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002417 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002418 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002419 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002420 int err;
2421
Johan Hedberga8a1d192011-11-10 15:54:38 +02002422 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002423 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2424 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002425
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002426 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002427 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2428 MGMT_STATUS_INVALID_PARAMS,
2429 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002430
Johan Hedberg118da702013-01-20 14:27:20 +02002431 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002432 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2433 MGMT_STATUS_INVALID_PARAMS,
2434 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002435
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002436 hci_dev_lock(hdev);
2437
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002438 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002439 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2440 MGMT_STATUS_NOT_POWERED, &rp,
2441 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002442 goto unlock;
2443 }
2444
Johan Hedberge0b2b272014-02-18 17:14:31 +02002445 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002446 /* If disconnection is requested, then look up the
2447 * connection. If the remote device is connected, it
2448 * will be later used to terminate the link.
2449 *
2450 * Setting it to NULL explicitly will cause no
2451 * termination of the link.
2452 */
2453 if (cp->disconnect)
2454 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2455 &cp->addr.bdaddr);
2456 else
2457 conn = NULL;
2458
Johan Hedberg124f6e32012-02-09 13:50:12 +02002459 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002460 if (err < 0) {
2461 err = mgmt_cmd_complete(sk, hdev->id,
2462 MGMT_OP_UNPAIR_DEVICE,
2463 MGMT_STATUS_NOT_PAIRED, &rp,
2464 sizeof(rp));
2465 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002466 }
2467
Johan Hedbergec182f02015-10-21 18:03:03 +03002468 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002469 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002470
Johan Hedbergec182f02015-10-21 18:03:03 +03002471 /* LE address type */
2472 addr_type = le_addr_type(cp->addr.type);
2473
Matias Karhumaacb28c302018-09-26 09:13:46 +03002474 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2475 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002476 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002477 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2478 MGMT_STATUS_NOT_PAIRED, &rp,
2479 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002480 goto unlock;
2481 }
2482
Johan Hedbergec182f02015-10-21 18:03:03 +03002483 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2484 if (!conn) {
2485 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2486 goto done;
2487 }
2488
Johan Hedbergc81d5552015-10-22 09:38:35 +03002489
Johan Hedbergec182f02015-10-21 18:03:03 +03002490 /* Defer clearing up the connection parameters until closing to
2491 * give a chance of keeping them if a repairing happens.
2492 */
2493 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2494
Johan Hedbergfc643612015-10-22 09:38:31 +03002495 /* Disable auto-connection parameters if present */
2496 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2497 if (params) {
2498 if (params->explicit_connect)
2499 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2500 else
2501 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2502 }
2503
Johan Hedbergec182f02015-10-21 18:03:03 +03002504 /* If disconnection is not requested, then clear the connection
2505 * variable so that the link is not terminated.
2506 */
2507 if (!cp->disconnect)
2508 conn = NULL;
2509
2510done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002511 /* If the connection variable is set, then termination of the
2512 * link is requested.
2513 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002514 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002515 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2516 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002517 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002518 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002519 }
2520
Johan Hedberg124f6e32012-02-09 13:50:12 +02002521 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002522 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002523 if (!cmd) {
2524 err = -ENOMEM;
2525 goto unlock;
2526 }
2527
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002528 cmd->cmd_complete = addr_cmd_complete;
2529
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002530 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002531 if (err < 0)
2532 mgmt_pending_remove(cmd);
2533
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002534unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002535 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002536 return err;
2537}
2538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002542 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002543 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002544 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002545 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002546 int err;
2547
Marcel Holtmann181d6952020-05-06 09:57:47 +02002548 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002549
Johan Hedberg06a63b12013-01-20 14:27:21 +02002550 memset(&rp, 0, sizeof(rp));
2551 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2552 rp.addr.type = cp->addr.type;
2553
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002554 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002555 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2556 MGMT_STATUS_INVALID_PARAMS,
2557 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002560
2561 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002562 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2563 MGMT_STATUS_NOT_POWERED, &rp,
2564 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565 goto failed;
2566 }
2567
Johan Hedberg333ae952015-03-17 13:48:47 +02002568 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002569 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2570 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002571 goto failed;
2572 }
2573
Andre Guedes591f47f2012-04-24 21:02:49 -03002574 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002575 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2576 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002577 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002578 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2579 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002580
Vishal Agarwalf9607272012-06-13 05:32:43 +05302581 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002582 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2583 MGMT_STATUS_NOT_CONNECTED, &rp,
2584 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002585 goto failed;
2586 }
2587
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002588 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002589 if (!cmd) {
2590 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002592 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002593
Johan Hedbergf5818c22014-12-05 13:36:02 +02002594 cmd->cmd_complete = generic_cmd_complete;
2595
Johan Hedberge3f2f922014-08-18 20:33:33 +03002596 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002597 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002598 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002599
2600failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002602 return err;
2603}
2604
Andre Guedes57c14772012-04-24 21:02:50 -03002605static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002606{
2607 switch (link_type) {
2608 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002609 switch (addr_type) {
2610 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002611 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002612
Johan Hedberg48264f02011-11-09 13:58:58 +02002613 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002614 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002615 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002616 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002617
Johan Hedberg4c659c32011-11-07 23:13:39 +02002618 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002619 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002620 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002621 }
2622}
2623
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002624static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2625 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002626{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002627 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002628 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002629 int err;
2630 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002631
Marcel Holtmann181d6952020-05-06 09:57:47 +02002632 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002634 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002635
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002636 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002637 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2638 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002639 goto unlock;
2640 }
2641
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002642 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002643 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2644 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002645 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002646 }
2647
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002648 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002649 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002650 err = -ENOMEM;
2651 goto unlock;
2652 }
2653
Johan Hedberg2784eb42011-01-21 13:56:35 +02002654 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002655 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002656 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2657 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002658 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002659 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002660 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002661 continue;
2662 i++;
2663 }
2664
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002665 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002666
Johan Hedberg4c659c32011-11-07 23:13:39 +02002667 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002668 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002669 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002670
Johan Hedberga38528f2011-01-22 06:46:43 +02002671 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002672
2673unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002674 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002675 return err;
2676}
2677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002680{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002681 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002682 int err;
2683
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002684 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002686 if (!cmd)
2687 return -ENOMEM;
2688
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002689 cmd->cmd_complete = addr_cmd_complete;
2690
Johan Hedbergd8457692012-02-17 14:24:57 +02002691 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002692 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002693 if (err < 0)
2694 mgmt_pending_remove(cmd);
2695
2696 return err;
2697}
2698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002702 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002703 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002704 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002705 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002706 int err;
2707
Marcel Holtmann181d6952020-05-06 09:57:47 +02002708 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002710 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002712 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002713 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2714 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715 goto failed;
2716 }
2717
Johan Hedbergd8457692012-02-17 14:24:57 +02002718 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002719 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002720 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2721 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002722 goto failed;
2723 }
2724
2725 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002726 struct mgmt_cp_pin_code_neg_reply ncp;
2727
2728 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002729
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002730 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002731
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002732 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002733 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002734 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2735 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002736
2737 goto failed;
2738 }
2739
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002740 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002741 if (!cmd) {
2742 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002743 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002744 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002745
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002746 cmd->cmd_complete = addr_cmd_complete;
2747
Johan Hedbergd8457692012-02-17 14:24:57 +02002748 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002749 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002750 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002751
2752 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2753 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002754 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002755
2756failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002757 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002758 return err;
2759}
2760
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2762 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002763{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002764 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002765
Marcel Holtmann181d6952020-05-06 09:57:47 +02002766 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002767
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002768 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002769 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2770 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002772 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002773
2774 hdev->io_capability = cp->io_capability;
2775
Marcel Holtmann181d6952020-05-06 09:57:47 +02002776 bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002778 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002779
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002780 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2781 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002782}
2783
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002784static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002785{
2786 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002787 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002788
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002789 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2791 continue;
2792
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793 if (cmd->user_data != conn)
2794 continue;
2795
2796 return cmd;
2797 }
2798
2799 return NULL;
2800}
2801
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002802static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002803{
2804 struct mgmt_rp_pair_device rp;
2805 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002806 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002807
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002808 bacpy(&rp.addr.bdaddr, &conn->dst);
2809 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002810
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002811 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2812 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002813
2814 /* So we don't get further callbacks for this connection */
2815 conn->connect_cfm_cb = NULL;
2816 conn->security_cfm_cb = NULL;
2817 conn->disconn_cfm_cb = NULL;
2818
David Herrmann76a68ba2013-04-06 20:28:37 +02002819 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002820
2821 /* The device is paired so there is no need to remove
2822 * its connection parameters anymore.
2823 */
2824 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002825
2826 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002827
2828 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002829}
2830
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002831void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2832{
2833 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002834 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002835
2836 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002837 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002838 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002839 mgmt_pending_remove(cmd);
2840 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002841}
2842
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2844{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002845 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002846
2847 BT_DBG("status %u", status);
2848
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002849 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002850 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002851 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002852 return;
2853 }
2854
2855 cmd->cmd_complete(cmd, mgmt_status(status));
2856 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002857}
2858
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002859static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302860{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002861 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302862
2863 BT_DBG("status %u", status);
2864
2865 if (!status)
2866 return;
2867
2868 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002869 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302870 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002871 return;
2872 }
2873
2874 cmd->cmd_complete(cmd, mgmt_status(status));
2875 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302876}
2877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002878static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002879 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002880{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002881 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002882 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002883 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002884 u8 sec_level, auth_type;
2885 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002886 int err;
2887
Marcel Holtmann181d6952020-05-06 09:57:47 +02002888 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002889
Szymon Jancf950a30e2013-01-18 12:48:07 +01002890 memset(&rp, 0, sizeof(rp));
2891 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2892 rp.addr.type = cp->addr.type;
2893
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002894 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002895 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2896 MGMT_STATUS_INVALID_PARAMS,
2897 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002898
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002899 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002900 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2901 MGMT_STATUS_INVALID_PARAMS,
2902 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002904 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002905
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002906 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002907 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2908 MGMT_STATUS_NOT_POWERED, &rp,
2909 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002910 goto unlock;
2911 }
2912
Johan Hedberg55e76b32015-03-10 22:34:40 +02002913 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2914 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2915 MGMT_STATUS_ALREADY_PAIRED, &rp,
2916 sizeof(rp));
2917 goto unlock;
2918 }
2919
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002920 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002921 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002922
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002923 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002924 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2925 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002926 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002927 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002928 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002929
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002930 /* When pairing a new device, it is expected to remember
2931 * this device for future connections. Adding the connection
2932 * parameter information ahead of time allows tracking
2933 * of the slave preferred values and will speed up any
2934 * further connection establishment.
2935 *
2936 * If connection parameters already exist, then they
2937 * will be kept and this function does nothing.
2938 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002939 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2940
2941 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2942 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002943
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002944 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2945 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002946 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002947 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002948
Ville Tervo30e76272011-02-22 16:10:53 -03002949 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002950 int status;
2951
2952 if (PTR_ERR(conn) == -EBUSY)
2953 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002954 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2955 status = MGMT_STATUS_NOT_SUPPORTED;
2956 else if (PTR_ERR(conn) == -ECONNREFUSED)
2957 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002958 else
2959 status = MGMT_STATUS_CONNECT_FAILED;
2960
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002961 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2962 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002963 goto unlock;
2964 }
2965
2966 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002967 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002968 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2969 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002970 goto unlock;
2971 }
2972
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002973 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002974 if (!cmd) {
2975 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002976 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002977 goto unlock;
2978 }
2979
Johan Hedberg04ab2742014-12-05 13:36:04 +02002980 cmd->cmd_complete = pairing_complete;
2981
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002982 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002983 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002984 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002985 conn->security_cfm_cb = pairing_complete_cb;
2986 conn->disconn_cfm_cb = pairing_complete_cb;
2987 } else {
2988 conn->connect_cfm_cb = le_pairing_complete_cb;
2989 conn->security_cfm_cb = le_pairing_complete_cb;
2990 conn->disconn_cfm_cb = le_pairing_complete_cb;
2991 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002992
Johan Hedberge9a416b2011-02-19 12:05:56 -03002993 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002994 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002995
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002996 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002997 hci_conn_security(conn, sec_level, auth_type, true)) {
2998 cmd->cmd_complete(cmd, 0);
2999 mgmt_pending_remove(cmd);
3000 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003001
3002 err = 0;
3003
3004unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003005 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003006 return err;
3007}
3008
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003009static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3010 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003011{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003012 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003013 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003014 struct hci_conn *conn;
3015 int err;
3016
Marcel Holtmann181d6952020-05-06 09:57:47 +02003017 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg28424702012-02-02 04:02:29 +02003018
Johan Hedberg28424702012-02-02 04:02:29 +02003019 hci_dev_lock(hdev);
3020
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003021 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003022 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3023 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003024 goto unlock;
3025 }
3026
Johan Hedberg333ae952015-03-17 13:48:47 +02003027 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003028 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003029 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3030 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003031 goto unlock;
3032 }
3033
3034 conn = cmd->user_data;
3035
3036 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003037 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003039 goto unlock;
3040 }
3041
Johan Hedberga511b352014-12-11 21:45:45 +02003042 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3043 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003044
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003045 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3046 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003047unlock:
3048 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003049 return err;
3050}
3051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003053 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003054 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003055{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003056 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003057 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003058 int err;
3059
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003060 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003061
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003062 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003063 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3064 MGMT_STATUS_NOT_POWERED, addr,
3065 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003066 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003067 }
3068
Johan Hedberg1707c602013-03-15 17:07:15 -05003069 if (addr->type == BDADDR_BREDR)
3070 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003071 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003072 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3073 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003074
Johan Hedberg272d90d2012-02-09 15:26:12 +02003075 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003076 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3077 MGMT_STATUS_NOT_CONNECTED, addr,
3078 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003079 goto done;
3080 }
3081
Johan Hedberg1707c602013-03-15 17:07:15 -05003082 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003083 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003084 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003085 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3086 MGMT_STATUS_SUCCESS, addr,
3087 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003088 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003089 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3090 MGMT_STATUS_FAILED, addr,
3091 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003092
Brian Gix47c15e22011-11-16 13:53:14 -08003093 goto done;
3094 }
3095
Johan Hedberg1707c602013-03-15 17:07:15 -05003096 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003097 if (!cmd) {
3098 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003099 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003100 }
3101
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003102 cmd->cmd_complete = addr_cmd_complete;
3103
Brian Gix0df4c182011-11-16 13:53:13 -08003104 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003105 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3106 struct hci_cp_user_passkey_reply cp;
3107
Johan Hedberg1707c602013-03-15 17:07:15 -05003108 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003109 cp.passkey = passkey;
3110 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3111 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003112 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3113 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003114
Johan Hedberga664b5b2011-02-19 12:06:02 -03003115 if (err < 0)
3116 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003117
Brian Gix0df4c182011-11-16 13:53:13 -08003118done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003119 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003120 return err;
3121}
3122
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303123static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3124 void *data, u16 len)
3125{
3126 struct mgmt_cp_pin_code_neg_reply *cp = data;
3127
Marcel Holtmann181d6952020-05-06 09:57:47 +02003128 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303129
Johan Hedberg1707c602013-03-15 17:07:15 -05003130 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303131 MGMT_OP_PIN_CODE_NEG_REPLY,
3132 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3133}
3134
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003135static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3136 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003137{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003138 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003139
Marcel Holtmann181d6952020-05-06 09:57:47 +02003140 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003141
3142 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003143 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3144 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003145
Johan Hedberg1707c602013-03-15 17:07:15 -05003146 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 MGMT_OP_USER_CONFIRM_REPLY,
3148 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003149}
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003153{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003154 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003155
Marcel Holtmann181d6952020-05-06 09:57:47 +02003156 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix0df4c182011-11-16 13:53:13 -08003157
Johan Hedberg1707c602013-03-15 17:07:15 -05003158 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003159 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3160 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003161}
3162
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003163static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3164 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003165{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003166 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003167
Marcel Holtmann181d6952020-05-06 09:57:47 +02003168 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003169
Johan Hedberg1707c602013-03-15 17:07:15 -05003170 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003171 MGMT_OP_USER_PASSKEY_REPLY,
3172 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003173}
3174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003175static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003176 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003177{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003178 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003179
Marcel Holtmann181d6952020-05-06 09:57:47 +02003180 bt_dev_dbg(hdev, "sock %p", sk);
Brian Gix604086b2011-11-23 08:28:33 -08003181
Johan Hedberg1707c602013-03-15 17:07:15 -05003182 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3184 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003185}
3186
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003187static void adv_expire(struct hci_dev *hdev, u32 flags)
3188{
3189 struct adv_info *adv_instance;
3190 struct hci_request req;
3191 int err;
3192
3193 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3194 if (!adv_instance)
3195 return;
3196
3197 /* stop if current instance doesn't need to be changed */
3198 if (!(adv_instance->flags & flags))
3199 return;
3200
3201 cancel_adv_timeout(hdev);
3202
3203 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3204 if (!adv_instance)
3205 return;
3206
3207 hci_req_init(&req, hdev);
3208 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3209 true);
3210 if (err)
3211 return;
3212
3213 hci_req_run(&req, NULL);
3214}
3215
Marcel Holtmann1904a852015-01-11 13:50:44 -08003216static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003217{
3218 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003219 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003220
Marcel Holtmann181d6952020-05-06 09:57:47 +02003221 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg13928972013-03-15 17:07:00 -05003222
3223 hci_dev_lock(hdev);
3224
Johan Hedberg333ae952015-03-17 13:48:47 +02003225 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003226 if (!cmd)
3227 goto unlock;
3228
3229 cp = cmd->param;
3230
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003231 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003232 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3233 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003234 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003235 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3236 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003237
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003238 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3239 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3240 }
3241
Johan Hedberg13928972013-03-15 17:07:00 -05003242 mgmt_pending_remove(cmd);
3243
3244unlock:
3245 hci_dev_unlock(hdev);
3246}
3247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003248static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003249 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003250{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003251 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003252 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003253 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003254 int err;
3255
Marcel Holtmann181d6952020-05-06 09:57:47 +02003256 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003258 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003259
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003260 /* If the old values are the same as the new ones just return a
3261 * direct command complete event.
3262 */
3263 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3264 !memcmp(hdev->short_name, cp->short_name,
3265 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003266 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3267 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003268 goto failed;
3269 }
3270
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003271 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003272
Johan Hedbergb5235a62012-02-21 14:32:24 +02003273 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003274 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003275
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003276 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3277 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003278 if (err < 0)
3279 goto failed;
3280
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003281 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3282 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003283 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003284
Johan Hedbergb5235a62012-02-21 14:32:24 +02003285 goto failed;
3286 }
3287
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003288 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003289 if (!cmd) {
3290 err = -ENOMEM;
3291 goto failed;
3292 }
3293
Johan Hedberg13928972013-03-15 17:07:00 -05003294 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3295
Johan Hedberg890ea892013-03-15 17:06:52 -05003296 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003297
3298 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003299 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003300 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003301 }
3302
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003303 /* The name is stored in the scan response data and so
3304 * no need to udpate the advertising data here.
3305 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003306 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003307 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003308
Johan Hedberg13928972013-03-15 17:07:00 -05003309 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003310 if (err < 0)
3311 mgmt_pending_remove(cmd);
3312
3313failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003314 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003315 return err;
3316}
3317
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003318static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3319 u16 len)
3320{
3321 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003322 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003323 int err;
3324
Marcel Holtmann181d6952020-05-06 09:57:47 +02003325 bt_dev_dbg(hdev, "sock %p", sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003326
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003327 if (!lmp_le_capable(hdev))
3328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3329 MGMT_STATUS_NOT_SUPPORTED);
3330
Alain Michaud6613bab2020-01-22 19:47:44 +00003331 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003332
3333 hci_dev_lock(hdev);
3334
Alain Michaud6613bab2020-01-22 19:47:44 +00003335 if (hdev->appearance != appearance) {
3336 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003337
3338 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3339 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003340
3341 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003342 }
3343
3344 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3345 0);
3346
3347 hci_dev_unlock(hdev);
3348
3349 return err;
3350}
3351
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303352static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3353 void *data, u16 len)
3354{
3355 struct mgmt_rp_get_phy_confguration rp;
3356
Marcel Holtmann181d6952020-05-06 09:57:47 +02003357 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303358
3359 hci_dev_lock(hdev);
3360
3361 memset(&rp, 0, sizeof(rp));
3362
3363 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3364 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3365 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3366
3367 hci_dev_unlock(hdev);
3368
3369 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3370 &rp, sizeof(rp));
3371}
3372
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303373int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3374{
3375 struct mgmt_ev_phy_configuration_changed ev;
3376
3377 memset(&ev, 0, sizeof(ev));
3378
3379 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3380
3381 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3382 sizeof(ev), skip);
3383}
3384
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303385static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3386 u16 opcode, struct sk_buff *skb)
3387{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303388 struct mgmt_pending_cmd *cmd;
3389
Marcel Holtmann181d6952020-05-06 09:57:47 +02003390 bt_dev_dbg(hdev, "status 0x%02x", status);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303391
3392 hci_dev_lock(hdev);
3393
3394 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3395 if (!cmd)
3396 goto unlock;
3397
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303398 if (status) {
3399 mgmt_cmd_status(cmd->sk, hdev->id,
3400 MGMT_OP_SET_PHY_CONFIGURATION,
3401 mgmt_status(status));
3402 } else {
3403 mgmt_cmd_complete(cmd->sk, hdev->id,
3404 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3405 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303406
3407 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303408 }
3409
3410 mgmt_pending_remove(cmd);
3411
3412unlock:
3413 hci_dev_unlock(hdev);
3414}
3415
3416static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3417 void *data, u16 len)
3418{
3419 struct mgmt_cp_set_phy_confguration *cp = data;
3420 struct hci_cp_le_set_default_phy cp_phy;
3421 struct mgmt_pending_cmd *cmd;
3422 struct hci_request req;
3423 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3424 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303425 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303426 int err;
3427
Marcel Holtmann181d6952020-05-06 09:57:47 +02003428 bt_dev_dbg(hdev, "sock %p", sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303429
3430 configurable_phys = get_configurable_phys(hdev);
3431 supported_phys = get_supported_phys(hdev);
3432 selected_phys = __le32_to_cpu(cp->selected_phys);
3433
3434 if (selected_phys & ~supported_phys)
3435 return mgmt_cmd_status(sk, hdev->id,
3436 MGMT_OP_SET_PHY_CONFIGURATION,
3437 MGMT_STATUS_INVALID_PARAMS);
3438
3439 unconfigure_phys = supported_phys & ~configurable_phys;
3440
3441 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3442 return mgmt_cmd_status(sk, hdev->id,
3443 MGMT_OP_SET_PHY_CONFIGURATION,
3444 MGMT_STATUS_INVALID_PARAMS);
3445
3446 if (selected_phys == get_selected_phys(hdev))
3447 return mgmt_cmd_complete(sk, hdev->id,
3448 MGMT_OP_SET_PHY_CONFIGURATION,
3449 0, NULL, 0);
3450
3451 hci_dev_lock(hdev);
3452
3453 if (!hdev_is_powered(hdev)) {
3454 err = mgmt_cmd_status(sk, hdev->id,
3455 MGMT_OP_SET_PHY_CONFIGURATION,
3456 MGMT_STATUS_REJECTED);
3457 goto unlock;
3458 }
3459
3460 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3461 err = mgmt_cmd_status(sk, hdev->id,
3462 MGMT_OP_SET_PHY_CONFIGURATION,
3463 MGMT_STATUS_BUSY);
3464 goto unlock;
3465 }
3466
3467 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3468 pkt_type |= (HCI_DH3 | HCI_DM3);
3469 else
3470 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3471
3472 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3473 pkt_type |= (HCI_DH5 | HCI_DM5);
3474 else
3475 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3476
3477 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3478 pkt_type &= ~HCI_2DH1;
3479 else
3480 pkt_type |= HCI_2DH1;
3481
3482 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3483 pkt_type &= ~HCI_2DH3;
3484 else
3485 pkt_type |= HCI_2DH3;
3486
3487 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3488 pkt_type &= ~HCI_2DH5;
3489 else
3490 pkt_type |= HCI_2DH5;
3491
3492 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3493 pkt_type &= ~HCI_3DH1;
3494 else
3495 pkt_type |= HCI_3DH1;
3496
3497 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3498 pkt_type &= ~HCI_3DH3;
3499 else
3500 pkt_type |= HCI_3DH3;
3501
3502 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3503 pkt_type &= ~HCI_3DH5;
3504 else
3505 pkt_type |= HCI_3DH5;
3506
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303507 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303508 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303509 changed = true;
3510 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303511
3512 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3513 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303514 if (changed)
3515 mgmt_phy_configuration_changed(hdev, sk);
3516
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303517 err = mgmt_cmd_complete(sk, hdev->id,
3518 MGMT_OP_SET_PHY_CONFIGURATION,
3519 0, NULL, 0);
3520
3521 goto unlock;
3522 }
3523
3524 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3525 len);
3526 if (!cmd) {
3527 err = -ENOMEM;
3528 goto unlock;
3529 }
3530
3531 hci_req_init(&req, hdev);
3532
3533 memset(&cp_phy, 0, sizeof(cp_phy));
3534
3535 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3536 cp_phy.all_phys |= 0x01;
3537
3538 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3539 cp_phy.all_phys |= 0x02;
3540
3541 if (selected_phys & MGMT_PHY_LE_1M_TX)
3542 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3543
3544 if (selected_phys & MGMT_PHY_LE_2M_TX)
3545 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3546
3547 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3548 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3549
3550 if (selected_phys & MGMT_PHY_LE_1M_RX)
3551 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3552
3553 if (selected_phys & MGMT_PHY_LE_2M_RX)
3554 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3555
3556 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3557 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3558
3559 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3560
3561 err = hci_req_run_skb(&req, set_default_phy_complete);
3562 if (err < 0)
3563 mgmt_pending_remove(cmd);
3564
3565unlock:
3566 hci_dev_unlock(hdev);
3567
3568 return err;
3569}
3570
Alain Michaud600a8742020-01-07 00:43:17 +00003571static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3572 u16 len)
3573{
3574 int err = MGMT_STATUS_SUCCESS;
3575 struct mgmt_cp_set_blocked_keys *keys = data;
3576 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3577 sizeof(struct mgmt_blocked_key_info));
3578 u16 key_count, expected_len;
3579 int i;
3580
Marcel Holtmann181d6952020-05-06 09:57:47 +02003581 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud600a8742020-01-07 00:43:17 +00003582
3583 key_count = __le16_to_cpu(keys->key_count);
3584 if (key_count > max_key_count) {
3585 bt_dev_err(hdev, "too big key_count value %u", key_count);
3586 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3587 MGMT_STATUS_INVALID_PARAMS);
3588 }
3589
3590 expected_len = struct_size(keys, keys, key_count);
3591 if (expected_len != len) {
3592 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3593 expected_len, len);
3594 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3595 MGMT_STATUS_INVALID_PARAMS);
3596 }
3597
3598 hci_dev_lock(hdev);
3599
3600 hci_blocked_keys_clear(hdev);
3601
3602 for (i = 0; i < keys->key_count; ++i) {
3603 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3604
3605 if (!b) {
3606 err = MGMT_STATUS_NO_RESOURCES;
3607 break;
3608 }
3609
3610 b->type = keys->keys[i].type;
3611 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3612 list_add_rcu(&b->list, &hdev->blocked_keys);
3613 }
3614 hci_dev_unlock(hdev);
3615
3616 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3617 err, NULL, 0);
3618}
3619
Alain Michaud00bce3f2020-03-05 16:14:59 +00003620static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3621 void *data, u16 len)
3622{
3623 struct mgmt_mode *cp = data;
3624 int err;
3625 bool changed = false;
3626
Marcel Holtmann181d6952020-05-06 09:57:47 +02003627 bt_dev_dbg(hdev, "sock %p", sk);
Alain Michaud00bce3f2020-03-05 16:14:59 +00003628
3629 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3630 return mgmt_cmd_status(sk, hdev->id,
3631 MGMT_OP_SET_WIDEBAND_SPEECH,
3632 MGMT_STATUS_NOT_SUPPORTED);
3633
3634 if (cp->val != 0x00 && cp->val != 0x01)
3635 return mgmt_cmd_status(sk, hdev->id,
3636 MGMT_OP_SET_WIDEBAND_SPEECH,
3637 MGMT_STATUS_INVALID_PARAMS);
3638
3639 hci_dev_lock(hdev);
3640
3641 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3642 err = mgmt_cmd_status(sk, hdev->id,
3643 MGMT_OP_SET_WIDEBAND_SPEECH,
3644 MGMT_STATUS_BUSY);
3645 goto unlock;
3646 }
3647
3648 if (hdev_is_powered(hdev) &&
3649 !!cp->val != hci_dev_test_flag(hdev,
3650 HCI_WIDEBAND_SPEECH_ENABLED)) {
3651 err = mgmt_cmd_status(sk, hdev->id,
3652 MGMT_OP_SET_WIDEBAND_SPEECH,
3653 MGMT_STATUS_REJECTED);
3654 goto unlock;
3655 }
3656
3657 if (cp->val)
3658 changed = !hci_dev_test_and_set_flag(hdev,
3659 HCI_WIDEBAND_SPEECH_ENABLED);
3660 else
3661 changed = hci_dev_test_and_clear_flag(hdev,
3662 HCI_WIDEBAND_SPEECH_ENABLED);
3663
3664 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3665 if (err < 0)
3666 goto unlock;
3667
3668 if (changed)
3669 err = new_settings(hdev, sk);
3670
3671unlock:
3672 hci_dev_unlock(hdev);
3673 return err;
3674}
3675
Marcel Holtmannbc292252020-04-03 21:44:05 +02003676static int read_security_info(struct sock *sk, struct hci_dev *hdev,
3677 void *data, u16 data_len)
3678{
3679 char buf[16];
3680 struct mgmt_rp_read_security_info *rp = (void *)buf;
3681 u16 sec_len = 0;
3682 u8 flags = 0;
3683
3684 bt_dev_dbg(hdev, "sock %p", sk);
3685
3686 memset(&buf, 0, sizeof(buf));
3687
3688 hci_dev_lock(hdev);
3689
3690 /* When the Read Simple Pairing Options command is supported, then
3691 * the remote public key validation is supported.
3692 */
3693 if (hdev->commands[41] & 0x08)
3694 flags |= 0x01; /* Remote public key validation (BR/EDR) */
3695
3696 flags |= 0x02; /* Remote public key validation (LE) */
3697
3698 /* When the Read Encryption Key Size command is supported, then the
3699 * encryption key size is enforced.
3700 */
3701 if (hdev->commands[20] & 0x10)
3702 flags |= 0x04; /* Encryption key size enforcement (BR/EDR) */
3703
3704 flags |= 0x08; /* Encryption key size enforcement (LE) */
3705
3706 sec_len = eir_append_data(rp->sec, sec_len, 0x01, &flags, 1);
3707
3708 /* When the Read Simple Pairing Options command is supported, then
3709 * also max encryption key size information is provided.
3710 */
3711 if (hdev->commands[41] & 0x08)
3712 sec_len = eir_append_le16(rp->sec, sec_len, 0x02,
3713 hdev->max_enc_key_size);
3714
3715 sec_len = eir_append_le16(rp->sec, sec_len, 0x03, SMP_MAX_ENC_KEY_SIZE);
3716
3717 rp->sec_len = cpu_to_le16(sec_len);
3718
3719 hci_dev_unlock(hdev);
3720
3721 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_SECURITY_INFO, 0,
3722 rp, sizeof(*rp) + sec_len);
3723}
3724
Marcel Holtmanne625e502020-05-06 09:57:52 +02003725#ifdef CONFIG_BT_FEATURE_DEBUG
3726/* d4992530-b9ec-469f-ab01-6c481c47da1c */
3727static const u8 debug_uuid[16] = {
3728 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab,
3729 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4,
3730};
3731#endif
3732
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003733static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3734 void *data, u16 data_len)
3735{
3736 char buf[42];
3737 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
3738 u16 idx = 0;
3739
3740 bt_dev_dbg(hdev, "sock %p", sk);
3741
3742 memset(&buf, 0, sizeof(buf));
3743
Marcel Holtmanne625e502020-05-06 09:57:52 +02003744#ifdef CONFIG_BT_FEATURE_DEBUG
3745 if (!hdev) {
3746 u32 flags = bt_dbg_get() ? BIT(0) : 0;
3747
3748 memcpy(rp->features[idx].uuid, debug_uuid, 16);
3749 rp->features[idx].flags = cpu_to_le32(flags);
3750 idx++;
3751 }
3752#endif
3753
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003754 rp->feature_count = cpu_to_le16(idx);
3755
3756 /* After reading the experimental features information, enable
3757 * the events to update client on any future change.
3758 */
3759 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3760
3761 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3762 MGMT_OP_READ_EXP_FEATURES_INFO,
3763 0, rp, sizeof(*rp) + (20 * idx));
3764}
3765
Marcel Holtmanne625e502020-05-06 09:57:52 +02003766#ifdef CONFIG_BT_FEATURE_DEBUG
3767static int exp_debug_feature_changed(bool enabled, struct sock *skip)
3768{
3769 struct mgmt_ev_exp_feature_changed ev;
3770
3771 memset(&ev, 0, sizeof(ev));
3772 memcpy(ev.uuid, debug_uuid, 16);
3773 ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
3774
3775 return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
3776 &ev, sizeof(ev),
3777 HCI_MGMT_EXP_FEATURE_EVENTS, skip);
3778}
3779#endif
3780
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003781static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3782 void *data, u16 data_len)
3783{
3784 struct mgmt_cp_set_exp_feature *cp = data;
3785 struct mgmt_rp_set_exp_feature rp;
3786
3787 bt_dev_dbg(hdev, "sock %p", sk);
3788
3789 if (!memcmp(cp->uuid, ZERO_KEY, 16)) {
3790 memset(rp.uuid, 0, 16);
3791 rp.flags = cpu_to_le32(0);
3792
Marcel Holtmanne625e502020-05-06 09:57:52 +02003793#ifdef CONFIG_BT_FEATURE_DEBUG
3794 if (!hdev) {
3795 bool changed = bt_dbg_get();
3796
3797 bt_dbg_set(false);
3798
3799 if (changed)
3800 exp_debug_feature_changed(false, sk);
3801 }
3802#endif
3803
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003804 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3805
3806 return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3807 MGMT_OP_SET_EXP_FEATURE, 0,
3808 &rp, sizeof(rp));
3809 }
3810
Marcel Holtmanne625e502020-05-06 09:57:52 +02003811#ifdef CONFIG_BT_FEATURE_DEBUG
3812 if (!memcmp(cp->uuid, debug_uuid, 16)) {
3813 bool val, changed;
3814 int err;
3815
3816 /* Command requires to use the non-controller index */
3817 if (hdev)
3818 return mgmt_cmd_status(sk, hdev->id,
3819 MGMT_OP_SET_EXP_FEATURE,
3820 MGMT_STATUS_INVALID_INDEX);
3821
3822 /* Parameters are limited to a single octet */
3823 if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
3824 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3825 MGMT_OP_SET_EXP_FEATURE,
3826 MGMT_STATUS_INVALID_PARAMS);
3827
3828 /* Only boolean on/off is supported */
3829 if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
3830 return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
3831 MGMT_OP_SET_EXP_FEATURE,
3832 MGMT_STATUS_INVALID_PARAMS);
3833
3834 val = !!cp->param[0];
3835 changed = val ? !bt_dbg_get() : bt_dbg_get();
3836 bt_dbg_set(val);
3837
3838 memcpy(rp.uuid, debug_uuid, 16);
3839 rp.flags = cpu_to_le32(val ? BIT(0) : 0);
3840
3841 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
3842
3843 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
3844 MGMT_OP_SET_EXP_FEATURE, 0,
3845 &rp, sizeof(rp));
3846
3847 if (changed)
3848 exp_debug_feature_changed(val, sk);
3849
3850 return err;
3851 }
3852#endif
3853
Marcel Holtmanna10c9072020-05-06 09:57:51 +02003854 return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE,
3855 MGMT_OP_SET_EXP_FEATURE,
3856 MGMT_STATUS_NOT_SUPPORTED);
3857}
3858
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003859static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3860 u16 opcode, struct sk_buff *skb)
3861{
3862 struct mgmt_rp_read_local_oob_data mgmt_rp;
3863 size_t rp_size = sizeof(mgmt_rp);
3864 struct mgmt_pending_cmd *cmd;
3865
Marcel Holtmann181d6952020-05-06 09:57:47 +02003866 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003867
3868 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3869 if (!cmd)
3870 return;
3871
3872 if (status || !skb) {
3873 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3874 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3875 goto remove;
3876 }
3877
3878 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3879
3880 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3881 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3882
3883 if (skb->len < sizeof(*rp)) {
3884 mgmt_cmd_status(cmd->sk, hdev->id,
3885 MGMT_OP_READ_LOCAL_OOB_DATA,
3886 MGMT_STATUS_FAILED);
3887 goto remove;
3888 }
3889
3890 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3891 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3892
3893 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3894 } else {
3895 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3896
3897 if (skb->len < sizeof(*rp)) {
3898 mgmt_cmd_status(cmd->sk, hdev->id,
3899 MGMT_OP_READ_LOCAL_OOB_DATA,
3900 MGMT_STATUS_FAILED);
3901 goto remove;
3902 }
3903
3904 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3905 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3906
3907 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3908 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3909 }
3910
3911 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3912 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3913
3914remove:
3915 mgmt_pending_remove(cmd);
3916}
3917
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003918static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003919 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003920{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003921 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003922 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003923 int err;
3924
Marcel Holtmann181d6952020-05-06 09:57:47 +02003925 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Jancc35938b2011-03-22 13:12:21 +01003926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003927 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003928
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003929 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003930 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3931 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003932 goto unlock;
3933 }
3934
Andre Guedes9a1a1992012-07-24 15:03:48 -03003935 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003936 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3937 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003938 goto unlock;
3939 }
3940
Johan Hedberg333ae952015-03-17 13:48:47 +02003941 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003942 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3943 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003944 goto unlock;
3945 }
3946
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003947 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003948 if (!cmd) {
3949 err = -ENOMEM;
3950 goto unlock;
3951 }
3952
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003953 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003954
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003955 if (bredr_sc_enabled(hdev))
3956 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3957 else
3958 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3959
3960 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003961 if (err < 0)
3962 mgmt_pending_remove(cmd);
3963
3964unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003965 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003966 return err;
3967}
3968
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003969static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003970 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003971{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003972 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003973 int err;
3974
Marcel Holtmann181d6952020-05-06 09:57:47 +02003975 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01003976
Johan Hedberg5d57e792015-01-23 10:10:38 +02003977 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003978 return mgmt_cmd_complete(sk, hdev->id,
3979 MGMT_OP_ADD_REMOTE_OOB_DATA,
3980 MGMT_STATUS_INVALID_PARAMS,
3981 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003982
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003983 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003984
Marcel Holtmannec109112014-01-10 02:07:30 -08003985 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3986 struct mgmt_cp_add_remote_oob_data *cp = data;
3987 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003988
Johan Hedbergc19a4952014-11-17 20:52:19 +02003989 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003990 err = mgmt_cmd_complete(sk, hdev->id,
3991 MGMT_OP_ADD_REMOTE_OOB_DATA,
3992 MGMT_STATUS_INVALID_PARAMS,
3993 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003994 goto unlock;
3995 }
3996
Marcel Holtmannec109112014-01-10 02:07:30 -08003997 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003998 cp->addr.type, cp->hash,
3999 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08004000 if (err < 0)
4001 status = MGMT_STATUS_FAILED;
4002 else
4003 status = MGMT_STATUS_SUCCESS;
4004
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004005 err = mgmt_cmd_complete(sk, hdev->id,
4006 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
4007 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004008 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
4009 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004010 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08004011 u8 status;
4012
Johan Hedberg86df9202014-10-26 20:52:27 +01004013 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004014 /* Enforce zero-valued 192-bit parameters as
4015 * long as legacy SMP OOB isn't implemented.
4016 */
4017 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
4018 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004019 err = mgmt_cmd_complete(sk, hdev->id,
4020 MGMT_OP_ADD_REMOTE_OOB_DATA,
4021 MGMT_STATUS_INVALID_PARAMS,
4022 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02004023 goto unlock;
4024 }
4025
Johan Hedberg86df9202014-10-26 20:52:27 +01004026 rand192 = NULL;
4027 hash192 = NULL;
4028 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004029 /* In case one of the P-192 values is set to zero,
4030 * then just disable OOB data for P-192.
4031 */
4032 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
4033 !memcmp(cp->hash192, ZERO_KEY, 16)) {
4034 rand192 = NULL;
4035 hash192 = NULL;
4036 } else {
4037 rand192 = cp->rand192;
4038 hash192 = cp->hash192;
4039 }
4040 }
4041
4042 /* In case one of the P-256 values is set to zero, then just
4043 * disable OOB data for P-256.
4044 */
4045 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
4046 !memcmp(cp->hash256, ZERO_KEY, 16)) {
4047 rand256 = NULL;
4048 hash256 = NULL;
4049 } else {
4050 rand256 = cp->rand256;
4051 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01004052 }
4053
Johan Hedberg81328d5c2014-10-26 20:33:47 +01004054 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01004055 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08004056 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08004057 if (err < 0)
4058 status = MGMT_STATUS_FAILED;
4059 else
4060 status = MGMT_STATUS_SUCCESS;
4061
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004062 err = mgmt_cmd_complete(sk, hdev->id,
4063 MGMT_OP_ADD_REMOTE_OOB_DATA,
4064 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08004065 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004066 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
4067 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004068 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
4069 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08004070 }
Szymon Janc2763eda2011-03-22 13:12:22 +01004071
Johan Hedbergc19a4952014-11-17 20:52:19 +02004072unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004073 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004074 return err;
4075}
4076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004077static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004078 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01004079{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004080 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004081 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01004082 int err;
4083
Marcel Holtmann181d6952020-05-06 09:57:47 +02004084 bt_dev_dbg(hdev, "sock %p", sk);
Szymon Janc2763eda2011-03-22 13:12:22 +01004085
Johan Hedbergc19a4952014-11-17 20:52:19 +02004086 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004087 return mgmt_cmd_complete(sk, hdev->id,
4088 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4089 MGMT_STATUS_INVALID_PARAMS,
4090 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004092 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004093
Johan Hedbergeedbd582014-11-15 09:34:23 +02004094 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4095 hci_remote_oob_data_clear(hdev);
4096 status = MGMT_STATUS_SUCCESS;
4097 goto done;
4098 }
4099
Johan Hedberg6928a922014-10-26 20:46:09 +01004100 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004101 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004102 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004103 else
Szymon Janca6785be2012-12-13 15:11:21 +01004104 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004105
Johan Hedbergeedbd582014-11-15 09:34:23 +02004106done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004107 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4108 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004110 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004111 return err;
4112}
4113
Johan Hedberge68f0722015-11-11 08:30:30 +02004114void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03004115{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004116 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004117
Marcel Holtmann181d6952020-05-06 09:57:47 +02004118 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes7c307722013-04-30 15:29:28 -03004119
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004120 hci_dev_lock(hdev);
4121
Johan Hedberg333ae952015-03-17 13:48:47 +02004122 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004123 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004124 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004125
Johan Hedberg78b781c2016-01-05 13:19:32 +02004126 if (!cmd)
4127 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
4128
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004129 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004130 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004131 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004132 }
4133
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004134 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004135
4136 /* Handle suspend notifier */
4137 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
4138 hdev->suspend_tasks)) {
4139 bt_dev_dbg(hdev, "Unpaused discovery");
4140 wake_up(&hdev->suspend_wait_q);
4141 }
Andre Guedes7c307722013-04-30 15:29:28 -03004142}
4143
Johan Hedberg591752a2015-11-11 08:11:24 +02004144static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
4145 uint8_t *mgmt_status)
4146{
4147 switch (type) {
4148 case DISCOV_TYPE_LE:
4149 *mgmt_status = mgmt_le_support(hdev);
4150 if (*mgmt_status)
4151 return false;
4152 break;
4153 case DISCOV_TYPE_INTERLEAVED:
4154 *mgmt_status = mgmt_le_support(hdev);
4155 if (*mgmt_status)
4156 return false;
4157 /* Intentional fall-through */
4158 case DISCOV_TYPE_BREDR:
4159 *mgmt_status = mgmt_bredr_support(hdev);
4160 if (*mgmt_status)
4161 return false;
4162 break;
4163 default:
4164 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
4165 return false;
4166 }
4167
4168 return true;
4169}
4170
Johan Hedberg78b781c2016-01-05 13:19:32 +02004171static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
4172 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004173{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004174 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004175 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01004176 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004177 int err;
4178
Marcel Holtmann181d6952020-05-06 09:57:47 +02004179 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004181 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004182
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004183 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004184 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004185 MGMT_STATUS_NOT_POWERED,
4186 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004187 goto failed;
4188 }
4189
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004190 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004191 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004192 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4193 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004194 goto failed;
4195 }
4196
Johan Hedberg591752a2015-11-11 08:11:24 +02004197 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004198 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4199 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004200 goto failed;
4201 }
4202
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004203 /* Can't start discovery when it is paused */
4204 if (hdev->discovery_paused) {
4205 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4206 &cp->type, sizeof(cp->type));
4207 goto failed;
4208 }
4209
Marcel Holtmann22078802014-12-05 11:45:22 +01004210 /* Clear the discovery filter first to free any previously
4211 * allocated memory for the UUID list.
4212 */
4213 hci_discovery_filter_clear(hdev);
4214
Andre Guedes4aab14e2012-02-17 20:39:36 -03004215 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004216 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004217 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4218 hdev->discovery.limited = true;
4219 else
4220 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004221
Johan Hedberg78b781c2016-01-05 13:19:32 +02004222 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004223 if (!cmd) {
4224 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004225 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004226 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004227
Johan Hedberge68f0722015-11-11 08:30:30 +02004228 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004229
4230 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004231 queue_work(hdev->req_workqueue, &hdev->discov_update);
4232 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004233
4234failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004235 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004236 return err;
4237}
4238
Johan Hedberg78b781c2016-01-05 13:19:32 +02004239static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4240 void *data, u16 len)
4241{
4242 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4243 data, len);
4244}
4245
4246static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4247 void *data, u16 len)
4248{
4249 return start_discovery_internal(sk, hdev,
4250 MGMT_OP_START_LIMITED_DISCOVERY,
4251 data, len);
4252}
4253
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004254static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4255 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004256{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004257 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4258 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004259}
4260
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004261static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4262 void *data, u16 len)
4263{
4264 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004265 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004266 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4267 u16 uuid_count, expected_len;
4268 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004269 int err;
4270
Marcel Holtmann181d6952020-05-06 09:57:47 +02004271 bt_dev_dbg(hdev, "sock %p", sk);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004272
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004273 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004274
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004275 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004276 err = mgmt_cmd_complete(sk, hdev->id,
4277 MGMT_OP_START_SERVICE_DISCOVERY,
4278 MGMT_STATUS_NOT_POWERED,
4279 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004280 goto failed;
4281 }
4282
4283 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004284 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004285 err = mgmt_cmd_complete(sk, hdev->id,
4286 MGMT_OP_START_SERVICE_DISCOVERY,
4287 MGMT_STATUS_BUSY, &cp->type,
4288 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004289 goto failed;
4290 }
4291
4292 uuid_count = __le16_to_cpu(cp->uuid_count);
4293 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004294 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4295 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004296 err = mgmt_cmd_complete(sk, hdev->id,
4297 MGMT_OP_START_SERVICE_DISCOVERY,
4298 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4299 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004300 goto failed;
4301 }
4302
4303 expected_len = sizeof(*cp) + uuid_count * 16;
4304 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004305 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4306 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004307 err = mgmt_cmd_complete(sk, hdev->id,
4308 MGMT_OP_START_SERVICE_DISCOVERY,
4309 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4310 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004311 goto failed;
4312 }
4313
Johan Hedberg591752a2015-11-11 08:11:24 +02004314 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4315 err = mgmt_cmd_complete(sk, hdev->id,
4316 MGMT_OP_START_SERVICE_DISCOVERY,
4317 status, &cp->type, sizeof(cp->type));
4318 goto failed;
4319 }
4320
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004321 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004322 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004323 if (!cmd) {
4324 err = -ENOMEM;
4325 goto failed;
4326 }
4327
Johan Hedberg2922a942014-12-05 13:36:06 +02004328 cmd->cmd_complete = service_discovery_cmd_complete;
4329
Marcel Holtmann22078802014-12-05 11:45:22 +01004330 /* Clear the discovery filter first to free any previously
4331 * allocated memory for the UUID list.
4332 */
4333 hci_discovery_filter_clear(hdev);
4334
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004335 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004336 hdev->discovery.type = cp->type;
4337 hdev->discovery.rssi = cp->rssi;
4338 hdev->discovery.uuid_count = uuid_count;
4339
4340 if (uuid_count > 0) {
4341 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4342 GFP_KERNEL);
4343 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004344 err = mgmt_cmd_complete(sk, hdev->id,
4345 MGMT_OP_START_SERVICE_DISCOVERY,
4346 MGMT_STATUS_FAILED,
4347 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004348 mgmt_pending_remove(cmd);
4349 goto failed;
4350 }
4351 }
4352
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004353 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004354 queue_work(hdev->req_workqueue, &hdev->discov_update);
4355 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004356
4357failed:
4358 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004359 return err;
4360}
4361
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004362void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004363{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004364 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004365
Marcel Holtmann181d6952020-05-06 09:57:47 +02004366 bt_dev_dbg(hdev, "status %d", status);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004367
4368 hci_dev_lock(hdev);
4369
Johan Hedberg333ae952015-03-17 13:48:47 +02004370 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004371 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004372 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004373 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004374 }
4375
Andre Guedes0e05bba2013-04-30 15:29:33 -03004376 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004377
4378 /* Handle suspend notifier */
4379 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4380 bt_dev_dbg(hdev, "Paused discovery");
4381 wake_up(&hdev->suspend_wait_q);
4382 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004383}
4384
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004385static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004386 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004387{
Johan Hedbergd9306502012-02-20 23:25:18 +02004388 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004389 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004390 int err;
4391
Marcel Holtmann181d6952020-05-06 09:57:47 +02004392 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg14a53662011-04-27 10:29:56 -04004393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004394 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004395
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004396 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004397 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4398 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4399 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004400 goto unlock;
4401 }
4402
4403 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004404 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4405 MGMT_STATUS_INVALID_PARAMS,
4406 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004407 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004408 }
4409
Johan Hedberg2922a942014-12-05 13:36:06 +02004410 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004411 if (!cmd) {
4412 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004413 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004414 }
4415
Johan Hedberg2922a942014-12-05 13:36:06 +02004416 cmd->cmd_complete = generic_cmd_complete;
4417
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004418 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4419 queue_work(hdev->req_workqueue, &hdev->discov_update);
4420 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004421
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004422unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004423 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004424 return err;
4425}
4426
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004427static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004428 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004429{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004430 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004431 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004432 int err;
4433
Marcel Holtmann181d6952020-05-06 09:57:47 +02004434 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004435
Johan Hedberg561aafb2012-01-04 13:31:59 +02004436 hci_dev_lock(hdev);
4437
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004438 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004439 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4440 MGMT_STATUS_FAILED, &cp->addr,
4441 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004442 goto failed;
4443 }
4444
Johan Hedberga198e7b2012-02-17 14:27:06 +02004445 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004446 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004447 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4448 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4449 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004450 goto failed;
4451 }
4452
4453 if (cp->name_known) {
4454 e->name_state = NAME_KNOWN;
4455 list_del(&e->list);
4456 } else {
4457 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004458 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004459 }
4460
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004461 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4462 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004463
4464failed:
4465 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004466 return err;
4467}
4468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004469static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004470 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004471{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004472 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004473 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004474 int err;
4475
Marcel Holtmann181d6952020-05-06 09:57:47 +02004476 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004477
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004478 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004479 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4480 MGMT_STATUS_INVALID_PARAMS,
4481 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004483 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004484
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004485 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4486 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004487 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004488 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004489 goto done;
4490 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004491
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004492 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4493 sk);
4494 status = MGMT_STATUS_SUCCESS;
4495
4496done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004497 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4498 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004500 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004501
4502 return err;
4503}
4504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004505static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004506 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004508 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004509 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004510 int err;
4511
Marcel Holtmann181d6952020-05-06 09:57:47 +02004512 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julku7fbec222011-06-15 12:01:15 +03004513
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004514 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004515 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4516 MGMT_STATUS_INVALID_PARAMS,
4517 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004519 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004520
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004521 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4522 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004523 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004524 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004525 goto done;
4526 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004527
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004528 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4529 sk);
4530 status = MGMT_STATUS_SUCCESS;
4531
4532done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004533 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4534 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004535
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004536 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004537
4538 return err;
4539}
4540
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004541static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4542 u16 len)
4543{
4544 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004545 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004546 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004547 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004548
Marcel Holtmann181d6952020-05-06 09:57:47 +02004549 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004550
Szymon Jancc72d4b82012-03-16 16:02:57 +01004551 source = __le16_to_cpu(cp->source);
4552
4553 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004554 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4555 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004556
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004557 hci_dev_lock(hdev);
4558
Szymon Jancc72d4b82012-03-16 16:02:57 +01004559 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004560 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4561 hdev->devid_product = __le16_to_cpu(cp->product);
4562 hdev->devid_version = __le16_to_cpu(cp->version);
4563
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004564 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4565 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004566
Johan Hedberg890ea892013-03-15 17:06:52 -05004567 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004568 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004569 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004570
4571 hci_dev_unlock(hdev);
4572
4573 return err;
4574}
4575
Arman Uguray24b4f382015-03-23 15:57:12 -07004576static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4577 u16 opcode)
4578{
Marcel Holtmann181d6952020-05-06 09:57:47 +02004579 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07004580}
4581
Marcel Holtmann1904a852015-01-11 13:50:44 -08004582static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4583 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004584{
4585 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004586 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004587 u8 instance;
4588 struct adv_info *adv_instance;
4589 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004590
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304591 hci_dev_lock(hdev);
4592
Johan Hedberg4375f102013-09-25 13:26:10 +03004593 if (status) {
4594 u8 mgmt_err = mgmt_status(status);
4595
4596 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4597 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304598 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004599 }
4600
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004601 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004602 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004603 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004604 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004605
Johan Hedberg4375f102013-09-25 13:26:10 +03004606 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4607 &match);
4608
4609 new_settings(hdev, match.sk);
4610
4611 if (match.sk)
4612 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304613
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004614 /* Handle suspend notifier */
4615 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
4616 hdev->suspend_tasks)) {
4617 bt_dev_dbg(hdev, "Paused advertising");
4618 wake_up(&hdev->suspend_wait_q);
4619 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
4620 hdev->suspend_tasks)) {
4621 bt_dev_dbg(hdev, "Unpaused advertising");
4622 wake_up(&hdev->suspend_wait_q);
4623 }
4624
Arman Uguray24b4f382015-03-23 15:57:12 -07004625 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004626 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004627 */
4628 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004629 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004630 goto unlock;
4631
Florian Grandel7816b822015-06-18 03:16:45 +02004632 instance = hdev->cur_adv_instance;
4633 if (!instance) {
4634 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4635 struct adv_info, list);
4636 if (!adv_instance)
4637 goto unlock;
4638
4639 instance = adv_instance->instance;
4640 }
4641
Arman Uguray24b4f382015-03-23 15:57:12 -07004642 hci_req_init(&req, hdev);
4643
Johan Hedbergf2252572015-11-18 12:49:20 +02004644 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004645
Florian Grandel7816b822015-06-18 03:16:45 +02004646 if (!err)
4647 err = hci_req_run(&req, enable_advertising_instance);
4648
4649 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004650 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004651
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304652unlock:
4653 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004654}
4655
Marcel Holtmann21b51872013-10-10 09:47:53 -07004656static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4657 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004658{
4659 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004660 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004661 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004662 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004663 int err;
4664
Marcel Holtmann181d6952020-05-06 09:57:47 +02004665 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg4375f102013-09-25 13:26:10 +03004666
Johan Hedberge6fe7982013-10-02 15:45:22 +03004667 status = mgmt_le_support(hdev);
4668 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004669 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4670 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004671
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004672 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004673 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4674 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004675
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004676 if (hdev->advertising_paused)
4677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4678 MGMT_STATUS_BUSY);
4679
Johan Hedberg4375f102013-09-25 13:26:10 +03004680 hci_dev_lock(hdev);
4681
4682 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004683
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004684 /* The following conditions are ones which mean that we should
4685 * not do any HCI communication but directly send a mgmt
4686 * response to user space (after toggling the flag if
4687 * necessary).
4688 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004689 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004690 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4691 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004692 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004693 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004694 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004695 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004696
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004697 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004698 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004699 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004700 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004701 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004702 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004703 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004704 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004705 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004706 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004707 }
4708
4709 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4710 if (err < 0)
4711 goto unlock;
4712
4713 if (changed)
4714 err = new_settings(hdev, sk);
4715
4716 goto unlock;
4717 }
4718
Johan Hedberg333ae952015-03-17 13:48:47 +02004719 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4720 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004721 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4722 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004723 goto unlock;
4724 }
4725
4726 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4727 if (!cmd) {
4728 err = -ENOMEM;
4729 goto unlock;
4730 }
4731
4732 hci_req_init(&req, hdev);
4733
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004734 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004735 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004736 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004737 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004738
Florian Grandel7816b822015-06-18 03:16:45 +02004739 cancel_adv_timeout(hdev);
4740
Arman Uguray24b4f382015-03-23 15:57:12 -07004741 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004742 /* Switch to instance "0" for the Set Advertising setting.
4743 * We cannot use update_[adv|scan_rsp]_data() here as the
4744 * HCI_ADVERTISING flag is not yet set.
4745 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004746 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304747
4748 if (ext_adv_capable(hdev)) {
4749 __hci_req_start_ext_adv(&req, 0x00);
4750 } else {
4751 __hci_req_update_adv_data(&req, 0x00);
4752 __hci_req_update_scan_rsp_data(&req, 0x00);
4753 __hci_req_enable_advertising(&req);
4754 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004755 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004756 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004757 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004758
4759 err = hci_req_run(&req, set_advertising_complete);
4760 if (err < 0)
4761 mgmt_pending_remove(cmd);
4762
4763unlock:
4764 hci_dev_unlock(hdev);
4765 return err;
4766}
4767
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004768static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4769 void *data, u16 len)
4770{
4771 struct mgmt_cp_set_static_address *cp = data;
4772 int err;
4773
Marcel Holtmann181d6952020-05-06 09:57:47 +02004774 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004775
Marcel Holtmann62af4442013-10-02 22:10:32 -07004776 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004777 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4778 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004779
4780 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004781 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4782 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004783
4784 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4785 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004786 return mgmt_cmd_status(sk, hdev->id,
4787 MGMT_OP_SET_STATIC_ADDRESS,
4788 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004789
4790 /* Two most significant bits shall be set */
4791 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004792 return mgmt_cmd_status(sk, hdev->id,
4793 MGMT_OP_SET_STATIC_ADDRESS,
4794 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004795 }
4796
4797 hci_dev_lock(hdev);
4798
4799 bacpy(&hdev->static_addr, &cp->bdaddr);
4800
Marcel Holtmann93690c22015-03-06 10:11:21 -08004801 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4802 if (err < 0)
4803 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004804
Marcel Holtmann93690c22015-03-06 10:11:21 -08004805 err = new_settings(hdev, sk);
4806
4807unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004808 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004809 return err;
4810}
4811
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004812static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4813 void *data, u16 len)
4814{
4815 struct mgmt_cp_set_scan_params *cp = data;
4816 __u16 interval, window;
4817 int err;
4818
Marcel Holtmann181d6952020-05-06 09:57:47 +02004819 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004820
4821 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4823 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004824
4825 interval = __le16_to_cpu(cp->interval);
4826
4827 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004828 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4829 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004830
4831 window = __le16_to_cpu(cp->window);
4832
4833 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004834 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4835 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004836
Marcel Holtmann899e1072013-10-14 09:55:32 -07004837 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004838 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4839 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004840
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004841 hci_dev_lock(hdev);
4842
4843 hdev->le_scan_interval = interval;
4844 hdev->le_scan_window = window;
4845
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004846 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4847 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004848
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004849 /* If background scan is running, restart it so new parameters are
4850 * loaded.
4851 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004852 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004853 hdev->discovery.state == DISCOVERY_STOPPED) {
4854 struct hci_request req;
4855
4856 hci_req_init(&req, hdev);
4857
4858 hci_req_add_le_scan_disable(&req);
4859 hci_req_add_le_passive_scan(&req);
4860
4861 hci_req_run(&req, NULL);
4862 }
4863
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004864 hci_dev_unlock(hdev);
4865
4866 return err;
4867}
4868
Marcel Holtmann1904a852015-01-11 13:50:44 -08004869static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4870 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004871{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004872 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004873
Marcel Holtmann181d6952020-05-06 09:57:47 +02004874 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004875
4876 hci_dev_lock(hdev);
4877
Johan Hedberg333ae952015-03-17 13:48:47 +02004878 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004879 if (!cmd)
4880 goto unlock;
4881
4882 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004883 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4884 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004885 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004886 struct mgmt_mode *cp = cmd->param;
4887
4888 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004889 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004890 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004891 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004892
Johan Hedberg33e38b32013-03-15 17:07:05 -05004893 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4894 new_settings(hdev, cmd->sk);
4895 }
4896
4897 mgmt_pending_remove(cmd);
4898
4899unlock:
4900 hci_dev_unlock(hdev);
4901}
4902
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004903static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004904 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004905{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004906 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004907 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004908 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004909 int err;
4910
Marcel Holtmann181d6952020-05-06 09:57:47 +02004911 bt_dev_dbg(hdev, "sock %p", sk);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004912
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004913 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004914 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004915 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4916 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004917
Johan Hedberga7e80f22013-01-09 16:05:19 +02004918 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004919 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4920 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004921
Antti Julkuf6422ec2011-06-22 13:11:56 +03004922 hci_dev_lock(hdev);
4923
Johan Hedberg333ae952015-03-17 13:48:47 +02004924 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004925 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4926 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004927 goto unlock;
4928 }
4929
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004930 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004931 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4932 hdev);
4933 goto unlock;
4934 }
4935
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004936 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004937 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004938 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4939 hdev);
4940 new_settings(hdev, sk);
4941 goto unlock;
4942 }
4943
Johan Hedberg33e38b32013-03-15 17:07:05 -05004944 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4945 data, len);
4946 if (!cmd) {
4947 err = -ENOMEM;
4948 goto unlock;
4949 }
4950
4951 hci_req_init(&req, hdev);
4952
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004953 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004954
4955 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004956 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004957 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4958 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004959 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004960 }
4961
Johan Hedberg33e38b32013-03-15 17:07:05 -05004962unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004963 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004964
Antti Julkuf6422ec2011-06-22 13:11:56 +03004965 return err;
4966}
4967
Marcel Holtmann1904a852015-01-11 13:50:44 -08004968static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004969{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004970 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004971
Marcel Holtmann181d6952020-05-06 09:57:47 +02004972 bt_dev_dbg(hdev, "status 0x%02x", status);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004973
4974 hci_dev_lock(hdev);
4975
Johan Hedberg333ae952015-03-17 13:48:47 +02004976 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004977 if (!cmd)
4978 goto unlock;
4979
4980 if (status) {
4981 u8 mgmt_err = mgmt_status(status);
4982
4983 /* We need to restore the flag if related HCI commands
4984 * failed.
4985 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004986 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004987
Johan Hedberga69e8372015-03-06 21:08:53 +02004988 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004989 } else {
4990 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4991 new_settings(hdev, cmd->sk);
4992 }
4993
4994 mgmt_pending_remove(cmd);
4995
4996unlock:
4997 hci_dev_unlock(hdev);
4998}
4999
5000static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5001{
5002 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005003 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005004 struct hci_request req;
5005 int err;
5006
Marcel Holtmann181d6952020-05-06 09:57:47 +02005007 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005008
5009 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005010 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5011 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005012
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005013 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005014 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5015 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005016
5017 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005018 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5019 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005020
5021 hci_dev_lock(hdev);
5022
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005023 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005024 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5025 goto unlock;
5026 }
5027
5028 if (!hdev_is_powered(hdev)) {
5029 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005030 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5031 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5032 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5033 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5034 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005035 }
5036
Marcel Holtmannce05d602015-03-13 02:11:03 -07005037 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005038
5039 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5040 if (err < 0)
5041 goto unlock;
5042
5043 err = new_settings(hdev, sk);
5044 goto unlock;
5045 }
5046
5047 /* Reject disabling when powered on */
5048 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005049 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5050 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005051 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005052 } else {
5053 /* When configuring a dual-mode controller to operate
5054 * with LE only and using a static address, then switching
5055 * BR/EDR back on is not allowed.
5056 *
5057 * Dual-mode controllers shall operate with the public
5058 * address as its identity address for BR/EDR and LE. So
5059 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005060 *
5061 * The same restrictions applies when secure connections
5062 * has been enabled. For BR/EDR this is a controller feature
5063 * while for LE it is a host stack feature. This means that
5064 * switching BR/EDR back on when secure connections has been
5065 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005066 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005067 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005068 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005069 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005070 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5071 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005072 goto unlock;
5073 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005074 }
5075
Johan Hedberg333ae952015-03-17 13:48:47 +02005076 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005077 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5078 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005079 goto unlock;
5080 }
5081
5082 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5083 if (!cmd) {
5084 err = -ENOMEM;
5085 goto unlock;
5086 }
5087
Johan Hedbergf2252572015-11-18 12:49:20 +02005088 /* We need to flip the bit already here so that
5089 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03005090 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005091 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005092
5093 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005094
Johan Hedbergbf943cb2015-11-25 16:15:43 +02005095 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005096 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005097
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005098 /* Since only the advertising data flags will change, there
5099 * is no need to update the scan response data.
5100 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02005101 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005102
Johan Hedberg0663ca22013-10-02 13:43:14 +03005103 err = hci_req_run(&req, set_bredr_complete);
5104 if (err < 0)
5105 mgmt_pending_remove(cmd);
5106
5107unlock:
5108 hci_dev_unlock(hdev);
5109 return err;
5110}
5111
Johan Hedberga1443f52015-01-23 15:42:46 +02005112static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5113{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005114 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005115 struct mgmt_mode *cp;
5116
Marcel Holtmann181d6952020-05-06 09:57:47 +02005117 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberga1443f52015-01-23 15:42:46 +02005118
5119 hci_dev_lock(hdev);
5120
Johan Hedberg333ae952015-03-17 13:48:47 +02005121 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005122 if (!cmd)
5123 goto unlock;
5124
5125 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005126 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5127 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005128 goto remove;
5129 }
5130
5131 cp = cmd->param;
5132
5133 switch (cp->val) {
5134 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005135 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5136 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005137 break;
5138 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005139 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005140 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005141 break;
5142 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005143 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5144 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005145 break;
5146 }
5147
5148 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5149 new_settings(hdev, cmd->sk);
5150
5151remove:
5152 mgmt_pending_remove(cmd);
5153unlock:
5154 hci_dev_unlock(hdev);
5155}
5156
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005157static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5158 void *data, u16 len)
5159{
5160 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005161 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005162 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005163 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005164 int err;
5165
Marcel Holtmann181d6952020-05-06 09:57:47 +02005166 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005167
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005168 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005169 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005170 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5171 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005172
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005173 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005174 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005175 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005176 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5177 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005178
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005179 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005180 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005181 MGMT_STATUS_INVALID_PARAMS);
5182
5183 hci_dev_lock(hdev);
5184
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005185 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005186 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005187 bool changed;
5188
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005189 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005190 changed = !hci_dev_test_and_set_flag(hdev,
5191 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005192 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005193 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005194 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005195 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005196 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005197 changed = hci_dev_test_and_clear_flag(hdev,
5198 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005199 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005200 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005201
5202 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5203 if (err < 0)
5204 goto failed;
5205
5206 if (changed)
5207 err = new_settings(hdev, sk);
5208
5209 goto failed;
5210 }
5211
Johan Hedberg333ae952015-03-17 13:48:47 +02005212 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005213 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5214 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005215 goto failed;
5216 }
5217
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005218 val = !!cp->val;
5219
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005220 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5221 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005222 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5223 goto failed;
5224 }
5225
5226 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5227 if (!cmd) {
5228 err = -ENOMEM;
5229 goto failed;
5230 }
5231
Johan Hedberga1443f52015-01-23 15:42:46 +02005232 hci_req_init(&req, hdev);
5233 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5234 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005235 if (err < 0) {
5236 mgmt_pending_remove(cmd);
5237 goto failed;
5238 }
5239
5240failed:
5241 hci_dev_unlock(hdev);
5242 return err;
5243}
5244
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005245static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5246 void *data, u16 len)
5247{
5248 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005249 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005250 int err;
5251
Marcel Holtmann181d6952020-05-06 09:57:47 +02005252 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005253
Johan Hedbergb97109792014-06-24 14:00:28 +03005254 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005255 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5256 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005257
5258 hci_dev_lock(hdev);
5259
5260 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005261 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005262 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005263 changed = hci_dev_test_and_clear_flag(hdev,
5264 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005265
Johan Hedbergb97109792014-06-24 14:00:28 +03005266 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005267 use_changed = !hci_dev_test_and_set_flag(hdev,
5268 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005269 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005270 use_changed = hci_dev_test_and_clear_flag(hdev,
5271 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005272
5273 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005274 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005275 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5276 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5277 sizeof(mode), &mode);
5278 }
5279
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005280 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5281 if (err < 0)
5282 goto unlock;
5283
5284 if (changed)
5285 err = new_settings(hdev, sk);
5286
5287unlock:
5288 hci_dev_unlock(hdev);
5289 return err;
5290}
5291
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005292static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5293 u16 len)
5294{
5295 struct mgmt_cp_set_privacy *cp = cp_data;
5296 bool changed;
5297 int err;
5298
Marcel Holtmann181d6952020-05-06 09:57:47 +02005299 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005300
5301 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005302 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5303 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005304
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005305 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005306 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5307 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005308
5309 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005310 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5311 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005312
5313 hci_dev_lock(hdev);
5314
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005315 /* If user space supports this command it is also expected to
5316 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5317 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005318 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005319
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005320 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005321 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005322 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005323 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305324 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005325 if (cp->privacy == 0x02)
5326 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5327 else
5328 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005329 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005330 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005331 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005332 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305333 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005334 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005335 }
5336
5337 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5338 if (err < 0)
5339 goto unlock;
5340
5341 if (changed)
5342 err = new_settings(hdev, sk);
5343
5344unlock:
5345 hci_dev_unlock(hdev);
5346 return err;
5347}
5348
Johan Hedberg41edf162014-02-18 10:19:35 +02005349static bool irk_is_valid(struct mgmt_irk_info *irk)
5350{
5351 switch (irk->addr.type) {
5352 case BDADDR_LE_PUBLIC:
5353 return true;
5354
5355 case BDADDR_LE_RANDOM:
5356 /* Two most significant bits shall be set */
5357 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5358 return false;
5359 return true;
5360 }
5361
5362 return false;
5363}
5364
5365static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5366 u16 len)
5367{
5368 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005369 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5370 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005371 u16 irk_count, expected_len;
5372 int i, err;
5373
Marcel Holtmann181d6952020-05-06 09:57:47 +02005374 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg41edf162014-02-18 10:19:35 +02005375
5376 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005377 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5378 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005379
5380 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005381 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005382 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5383 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005384 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5385 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005386 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005387
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005388 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005389 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005390 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5391 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005392 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5393 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005394 }
5395
Marcel Holtmann181d6952020-05-06 09:57:47 +02005396 bt_dev_dbg(hdev, "irk_count %u", irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005397
5398 for (i = 0; i < irk_count; i++) {
5399 struct mgmt_irk_info *key = &cp->irks[i];
5400
5401 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005402 return mgmt_cmd_status(sk, hdev->id,
5403 MGMT_OP_LOAD_IRKS,
5404 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005405 }
5406
5407 hci_dev_lock(hdev);
5408
5409 hci_smp_irks_clear(hdev);
5410
5411 for (i = 0; i < irk_count; i++) {
5412 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005413
Alain Michaud600a8742020-01-07 00:43:17 +00005414 if (hci_is_blocked_key(hdev,
5415 HCI_BLOCKED_KEY_TYPE_IRK,
5416 irk->val)) {
5417 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5418 &irk->addr.bdaddr);
5419 continue;
5420 }
5421
Johan Hedberg85813a72015-10-21 18:02:59 +03005422 hci_add_irk(hdev, &irk->addr.bdaddr,
5423 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005424 BDADDR_ANY);
5425 }
5426
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005427 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005428
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005429 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005430
5431 hci_dev_unlock(hdev);
5432
5433 return err;
5434}
5435
Johan Hedberg3f706b72013-01-20 14:27:16 +02005436static bool ltk_is_valid(struct mgmt_ltk_info *key)
5437{
5438 if (key->master != 0x00 && key->master != 0x01)
5439 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005440
5441 switch (key->addr.type) {
5442 case BDADDR_LE_PUBLIC:
5443 return true;
5444
5445 case BDADDR_LE_RANDOM:
5446 /* Two most significant bits shall be set */
5447 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5448 return false;
5449 return true;
5450 }
5451
5452 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005453}
5454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005455static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005456 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005457{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005458 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005459 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5460 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005461 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005462 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005463
Marcel Holtmann181d6952020-05-06 09:57:47 +02005464 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005465
5466 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005467 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5468 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005469
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005470 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005471 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005472 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5473 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005474 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5475 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005476 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005477
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005478 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005479 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005480 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5481 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5483 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005484 }
5485
Marcel Holtmann181d6952020-05-06 09:57:47 +02005486 bt_dev_dbg(hdev, "key_count %u", key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005487
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005488 for (i = 0; i < key_count; i++) {
5489 struct mgmt_ltk_info *key = &cp->keys[i];
5490
Johan Hedberg3f706b72013-01-20 14:27:16 +02005491 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005492 return mgmt_cmd_status(sk, hdev->id,
5493 MGMT_OP_LOAD_LONG_TERM_KEYS,
5494 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005495 }
5496
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005497 hci_dev_lock(hdev);
5498
5499 hci_smp_ltks_clear(hdev);
5500
5501 for (i = 0; i < key_count; i++) {
5502 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005503 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005504
Alain Michaud600a8742020-01-07 00:43:17 +00005505 if (hci_is_blocked_key(hdev,
5506 HCI_BLOCKED_KEY_TYPE_LTK,
5507 key->val)) {
5508 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5509 &key->addr.bdaddr);
5510 continue;
5511 }
5512
Johan Hedberg61b43352014-05-29 19:36:53 +03005513 switch (key->type) {
5514 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005515 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005516 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005517 break;
5518 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005519 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005520 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005521 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005522 case MGMT_LTK_P256_UNAUTH:
5523 authenticated = 0x00;
5524 type = SMP_LTK_P256;
5525 break;
5526 case MGMT_LTK_P256_AUTH:
5527 authenticated = 0x01;
5528 type = SMP_LTK_P256;
5529 break;
5530 case MGMT_LTK_P256_DEBUG:
5531 authenticated = 0x00;
5532 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005533 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005534 default:
5535 continue;
5536 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005537
Johan Hedberg85813a72015-10-21 18:02:59 +03005538 hci_add_ltk(hdev, &key->addr.bdaddr,
5539 le_addr_type(key->addr.type), type, authenticated,
5540 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005541 }
5542
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005543 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005544 NULL, 0);
5545
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005546 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005547
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005548 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005549}
5550
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005551static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005552{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005553 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005554 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005555 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005556
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005557 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005558
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005559 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005560 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005561 rp.tx_power = conn->tx_power;
5562 rp.max_tx_power = conn->max_tx_power;
5563 } else {
5564 rp.rssi = HCI_RSSI_INVALID;
5565 rp.tx_power = HCI_TX_POWER_INVALID;
5566 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005567 }
5568
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005569 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5570 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005571
5572 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005573 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005574
5575 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005576}
5577
Marcel Holtmann1904a852015-01-11 13:50:44 -08005578static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5579 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005580{
5581 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005582 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005583 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005584 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005585 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005586
Marcel Holtmann181d6952020-05-06 09:57:47 +02005587 bt_dev_dbg(hdev, "status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005588
5589 hci_dev_lock(hdev);
5590
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005591 /* Commands sent in request are either Read RSSI or Read Transmit Power
5592 * Level so we check which one was last sent to retrieve connection
5593 * handle. Both commands have handle as first parameter so it's safe to
5594 * cast data on the same command struct.
5595 *
5596 * First command sent is always Read RSSI and we fail only if it fails.
5597 * In other case we simply override error to indicate success as we
5598 * already remembered if TX power value is actually valid.
5599 */
5600 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5601 if (!cp) {
5602 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005603 status = MGMT_STATUS_SUCCESS;
5604 } else {
5605 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005606 }
5607
5608 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005609 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005610 goto unlock;
5611 }
5612
5613 handle = __le16_to_cpu(cp->handle);
5614 conn = hci_conn_hash_lookup_handle(hdev, handle);
5615 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005616 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5617 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005618 goto unlock;
5619 }
5620
Johan Hedberg333ae952015-03-17 13:48:47 +02005621 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005622 if (!cmd)
5623 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005624
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005625 cmd->cmd_complete(cmd, status);
5626 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005627
5628unlock:
5629 hci_dev_unlock(hdev);
5630}
5631
5632static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5633 u16 len)
5634{
5635 struct mgmt_cp_get_conn_info *cp = data;
5636 struct mgmt_rp_get_conn_info rp;
5637 struct hci_conn *conn;
5638 unsigned long conn_info_age;
5639 int err = 0;
5640
Marcel Holtmann181d6952020-05-06 09:57:47 +02005641 bt_dev_dbg(hdev, "sock %p", sk);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005642
5643 memset(&rp, 0, sizeof(rp));
5644 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5645 rp.addr.type = cp->addr.type;
5646
5647 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005648 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5649 MGMT_STATUS_INVALID_PARAMS,
5650 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005651
5652 hci_dev_lock(hdev);
5653
5654 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005655 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5656 MGMT_STATUS_NOT_POWERED, &rp,
5657 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005658 goto unlock;
5659 }
5660
5661 if (cp->addr.type == BDADDR_BREDR)
5662 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5663 &cp->addr.bdaddr);
5664 else
5665 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5666
5667 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005668 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5669 MGMT_STATUS_NOT_CONNECTED, &rp,
5670 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005671 goto unlock;
5672 }
5673
Johan Hedberg333ae952015-03-17 13:48:47 +02005674 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005675 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5676 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005677 goto unlock;
5678 }
5679
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005680 /* To avoid client trying to guess when to poll again for information we
5681 * calculate conn info age as random value between min/max set in hdev.
5682 */
5683 conn_info_age = hdev->conn_info_min_age +
5684 prandom_u32_max(hdev->conn_info_max_age -
5685 hdev->conn_info_min_age);
5686
5687 /* Query controller to refresh cached values if they are too old or were
5688 * never read.
5689 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005690 if (time_after(jiffies, conn->conn_info_timestamp +
5691 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005692 !conn->conn_info_timestamp) {
5693 struct hci_request req;
5694 struct hci_cp_read_tx_power req_txp_cp;
5695 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005696 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005697
5698 hci_req_init(&req, hdev);
5699 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5700 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5701 &req_rssi_cp);
5702
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005703 /* For LE links TX power does not change thus we don't need to
5704 * query for it once value is known.
5705 */
5706 if (!bdaddr_type_is_le(cp->addr.type) ||
5707 conn->tx_power == HCI_TX_POWER_INVALID) {
5708 req_txp_cp.handle = cpu_to_le16(conn->handle);
5709 req_txp_cp.type = 0x00;
5710 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5711 sizeof(req_txp_cp), &req_txp_cp);
5712 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005713
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005714 /* Max TX power needs to be read only once per connection */
5715 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5716 req_txp_cp.handle = cpu_to_le16(conn->handle);
5717 req_txp_cp.type = 0x01;
5718 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5719 sizeof(req_txp_cp), &req_txp_cp);
5720 }
5721
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005722 err = hci_req_run(&req, conn_info_refresh_complete);
5723 if (err < 0)
5724 goto unlock;
5725
5726 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5727 data, len);
5728 if (!cmd) {
5729 err = -ENOMEM;
5730 goto unlock;
5731 }
5732
5733 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005734 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005735 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005736
5737 conn->conn_info_timestamp = jiffies;
5738 } else {
5739 /* Cache is valid, just reply with values cached in hci_conn */
5740 rp.rssi = conn->rssi;
5741 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005742 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005743
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005744 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5745 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005746 }
5747
5748unlock:
5749 hci_dev_unlock(hdev);
5750 return err;
5751}
5752
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005753static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005754{
5755 struct hci_conn *conn = cmd->user_data;
5756 struct mgmt_rp_get_clock_info rp;
5757 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005758 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005759
5760 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005761 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005762
5763 if (status)
5764 goto complete;
5765
5766 hdev = hci_dev_get(cmd->index);
5767 if (hdev) {
5768 rp.local_clock = cpu_to_le32(hdev->clock);
5769 hci_dev_put(hdev);
5770 }
5771
5772 if (conn) {
5773 rp.piconet_clock = cpu_to_le32(conn->clock);
5774 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5775 }
5776
5777complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005778 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5779 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005780
5781 if (conn) {
5782 hci_conn_drop(conn);
5783 hci_conn_put(conn);
5784 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005785
5786 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005787}
5788
Marcel Holtmann1904a852015-01-11 13:50:44 -08005789static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005790{
Johan Hedberg95868422014-06-28 17:54:07 +03005791 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005792 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005793 struct hci_conn *conn;
5794
Marcel Holtmann181d6952020-05-06 09:57:47 +02005795 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg95868422014-06-28 17:54:07 +03005796
5797 hci_dev_lock(hdev);
5798
5799 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5800 if (!hci_cp)
5801 goto unlock;
5802
5803 if (hci_cp->which) {
5804 u16 handle = __le16_to_cpu(hci_cp->handle);
5805 conn = hci_conn_hash_lookup_handle(hdev, handle);
5806 } else {
5807 conn = NULL;
5808 }
5809
Johan Hedberg333ae952015-03-17 13:48:47 +02005810 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005811 if (!cmd)
5812 goto unlock;
5813
Johan Hedberg69487372014-12-05 13:36:07 +02005814 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005815 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005816
5817unlock:
5818 hci_dev_unlock(hdev);
5819}
5820
5821static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5822 u16 len)
5823{
5824 struct mgmt_cp_get_clock_info *cp = data;
5825 struct mgmt_rp_get_clock_info rp;
5826 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005827 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005828 struct hci_request req;
5829 struct hci_conn *conn;
5830 int err;
5831
Marcel Holtmann181d6952020-05-06 09:57:47 +02005832 bt_dev_dbg(hdev, "sock %p", sk);
Johan Hedberg95868422014-06-28 17:54:07 +03005833
5834 memset(&rp, 0, sizeof(rp));
5835 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5836 rp.addr.type = cp->addr.type;
5837
5838 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005839 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5840 MGMT_STATUS_INVALID_PARAMS,
5841 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005842
5843 hci_dev_lock(hdev);
5844
5845 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005846 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5847 MGMT_STATUS_NOT_POWERED, &rp,
5848 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005849 goto unlock;
5850 }
5851
5852 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5853 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5854 &cp->addr.bdaddr);
5855 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005856 err = mgmt_cmd_complete(sk, hdev->id,
5857 MGMT_OP_GET_CLOCK_INFO,
5858 MGMT_STATUS_NOT_CONNECTED,
5859 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005860 goto unlock;
5861 }
5862 } else {
5863 conn = NULL;
5864 }
5865
5866 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5867 if (!cmd) {
5868 err = -ENOMEM;
5869 goto unlock;
5870 }
5871
Johan Hedberg69487372014-12-05 13:36:07 +02005872 cmd->cmd_complete = clock_info_cmd_complete;
5873
Johan Hedberg95868422014-06-28 17:54:07 +03005874 hci_req_init(&req, hdev);
5875
5876 memset(&hci_cp, 0, sizeof(hci_cp));
5877 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5878
5879 if (conn) {
5880 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005881 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005882
5883 hci_cp.handle = cpu_to_le16(conn->handle);
5884 hci_cp.which = 0x01; /* Piconet clock */
5885 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5886 }
5887
5888 err = hci_req_run(&req, get_clock_info_complete);
5889 if (err < 0)
5890 mgmt_pending_remove(cmd);
5891
5892unlock:
5893 hci_dev_unlock(hdev);
5894 return err;
5895}
5896
Johan Hedberg5a154e62014-12-19 22:26:02 +02005897static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5898{
5899 struct hci_conn *conn;
5900
5901 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5902 if (!conn)
5903 return false;
5904
5905 if (conn->dst_type != type)
5906 return false;
5907
5908 if (conn->state != BT_CONNECTED)
5909 return false;
5910
5911 return true;
5912}
5913
5914/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005915static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005916 u8 addr_type, u8 auto_connect)
5917{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005918 struct hci_conn_params *params;
5919
5920 params = hci_conn_params_add(hdev, addr, addr_type);
5921 if (!params)
5922 return -EIO;
5923
5924 if (params->auto_connect == auto_connect)
5925 return 0;
5926
5927 list_del_init(&params->action);
5928
5929 switch (auto_connect) {
5930 case HCI_AUTO_CONN_DISABLED:
5931 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005932 /* If auto connect is being disabled when we're trying to
5933 * connect to device, keep connecting.
5934 */
5935 if (params->explicit_connect)
5936 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005937 break;
5938 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005939 if (params->explicit_connect)
5940 list_add(&params->action, &hdev->pend_le_conns);
5941 else
5942 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005943 break;
5944 case HCI_AUTO_CONN_DIRECT:
5945 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005946 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005947 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005948 break;
5949 }
5950
5951 params->auto_connect = auto_connect;
5952
Marcel Holtmann181d6952020-05-06 09:57:47 +02005953 bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
5954 addr, addr_type, auto_connect);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005955
5956 return 0;
5957}
5958
Marcel Holtmann8afef092014-06-29 22:28:34 +02005959static void device_added(struct sock *sk, struct hci_dev *hdev,
5960 bdaddr_t *bdaddr, u8 type, u8 action)
5961{
5962 struct mgmt_ev_device_added ev;
5963
5964 bacpy(&ev.addr.bdaddr, bdaddr);
5965 ev.addr.type = type;
5966 ev.action = action;
5967
5968 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5969}
5970
Marcel Holtmann2faade52014-06-29 19:44:03 +02005971static int add_device(struct sock *sk, struct hci_dev *hdev,
5972 void *data, u16 len)
5973{
5974 struct mgmt_cp_add_device *cp = data;
5975 u8 auto_conn, addr_type;
5976 int err;
5977
Marcel Holtmann181d6952020-05-06 09:57:47 +02005978 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005979
Johan Hedberg66593582014-07-09 12:59:14 +03005980 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005981 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005982 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5983 MGMT_STATUS_INVALID_PARAMS,
5984 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005985
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005986 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005987 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5988 MGMT_STATUS_INVALID_PARAMS,
5989 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005990
5991 hci_dev_lock(hdev);
5992
Johan Hedberg66593582014-07-09 12:59:14 +03005993 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005994 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005995 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005996 err = mgmt_cmd_complete(sk, hdev->id,
5997 MGMT_OP_ADD_DEVICE,
5998 MGMT_STATUS_INVALID_PARAMS,
5999 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006000 goto unlock;
6001 }
6002
6003 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
6004 cp->addr.type);
6005 if (err)
6006 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006007
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006008 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006009
Johan Hedberg66593582014-07-09 12:59:14 +03006010 goto added;
6011 }
6012
Johan Hedberg85813a72015-10-21 18:02:59 +03006013 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006014
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006015 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006016 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006017 else if (cp->action == 0x01)
6018 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006019 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006020 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006021
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006022 /* Kernel internally uses conn_params with resolvable private
6023 * address, but Add Device allows only identity addresses.
6024 * Make sure it is enforced before calling
6025 * hci_conn_params_lookup.
6026 */
6027 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006028 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6029 MGMT_STATUS_INVALID_PARAMS,
6030 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006031 goto unlock;
6032 }
6033
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006034 /* If the connection parameters don't exist for this device,
6035 * they will be created and configured with defaults.
6036 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02006037 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006038 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006039 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6040 MGMT_STATUS_FAILED, &cp->addr,
6041 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006042 goto unlock;
6043 }
6044
Johan Hedberg51d7a942015-11-11 08:11:18 +02006045 hci_update_background_scan(hdev);
6046
Johan Hedberg66593582014-07-09 12:59:14 +03006047added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006048 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
6049
Johan Hedberg51d7a942015-11-11 08:11:18 +02006050 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6051 MGMT_STATUS_SUCCESS, &cp->addr,
6052 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006053
6054unlock:
6055 hci_dev_unlock(hdev);
6056 return err;
6057}
6058
Marcel Holtmann8afef092014-06-29 22:28:34 +02006059static void device_removed(struct sock *sk, struct hci_dev *hdev,
6060 bdaddr_t *bdaddr, u8 type)
6061{
6062 struct mgmt_ev_device_removed ev;
6063
6064 bacpy(&ev.addr.bdaddr, bdaddr);
6065 ev.addr.type = type;
6066
6067 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6068}
6069
Marcel Holtmann2faade52014-06-29 19:44:03 +02006070static int remove_device(struct sock *sk, struct hci_dev *hdev,
6071 void *data, u16 len)
6072{
6073 struct mgmt_cp_remove_device *cp = data;
6074 int err;
6075
Marcel Holtmann181d6952020-05-06 09:57:47 +02006076 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006077
6078 hci_dev_lock(hdev);
6079
6080 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006081 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006082 u8 addr_type;
6083
Johan Hedberg66593582014-07-09 12:59:14 +03006084 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006085 err = mgmt_cmd_complete(sk, hdev->id,
6086 MGMT_OP_REMOVE_DEVICE,
6087 MGMT_STATUS_INVALID_PARAMS,
6088 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006089 goto unlock;
6090 }
6091
Johan Hedberg66593582014-07-09 12:59:14 +03006092 if (cp->addr.type == BDADDR_BREDR) {
6093 err = hci_bdaddr_list_del(&hdev->whitelist,
6094 &cp->addr.bdaddr,
6095 cp->addr.type);
6096 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006097 err = mgmt_cmd_complete(sk, hdev->id,
6098 MGMT_OP_REMOVE_DEVICE,
6099 MGMT_STATUS_INVALID_PARAMS,
6100 &cp->addr,
6101 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03006102 goto unlock;
6103 }
6104
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006105 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006106
Johan Hedberg66593582014-07-09 12:59:14 +03006107 device_removed(sk, hdev, &cp->addr.bdaddr,
6108 cp->addr.type);
6109 goto complete;
6110 }
6111
Johan Hedberg85813a72015-10-21 18:02:59 +03006112 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006113
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006114 /* Kernel internally uses conn_params with resolvable private
6115 * address, but Remove Device allows only identity addresses.
6116 * Make sure it is enforced before calling
6117 * hci_conn_params_lookup.
6118 */
6119 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006120 err = mgmt_cmd_complete(sk, hdev->id,
6121 MGMT_OP_REMOVE_DEVICE,
6122 MGMT_STATUS_INVALID_PARAMS,
6123 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02006124 goto unlock;
6125 }
6126
Johan Hedbergc71593d2014-07-02 17:37:28 +03006127 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6128 addr_type);
6129 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006130 err = mgmt_cmd_complete(sk, hdev->id,
6131 MGMT_OP_REMOVE_DEVICE,
6132 MGMT_STATUS_INVALID_PARAMS,
6133 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006134 goto unlock;
6135 }
6136
Johan Hedberg679d2b62015-10-16 10:07:52 +03006137 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
6138 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006139 err = mgmt_cmd_complete(sk, hdev->id,
6140 MGMT_OP_REMOVE_DEVICE,
6141 MGMT_STATUS_INVALID_PARAMS,
6142 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03006143 goto unlock;
6144 }
6145
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006146 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006147 list_del(&params->list);
6148 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02006149 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006150
6151 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006152 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006153 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006154 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006155
Marcel Holtmann2faade52014-06-29 19:44:03 +02006156 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02006157 err = mgmt_cmd_complete(sk, hdev->id,
6158 MGMT_OP_REMOVE_DEVICE,
6159 MGMT_STATUS_INVALID_PARAMS,
6160 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006161 goto unlock;
6162 }
6163
Johan Hedberg66593582014-07-09 12:59:14 +03006164 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6165 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6166 list_del(&b->list);
6167 kfree(b);
6168 }
6169
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006170 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03006171
Johan Hedberg19de0822014-07-06 13:06:51 +03006172 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6173 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6174 continue;
6175 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03006176 if (p->explicit_connect) {
6177 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
6178 continue;
6179 }
Johan Hedberg19de0822014-07-06 13:06:51 +03006180 list_del(&p->action);
6181 list_del(&p->list);
6182 kfree(p);
6183 }
6184
Marcel Holtmann181d6952020-05-06 09:57:47 +02006185 bt_dev_dbg(hdev, "All LE connection parameters were removed");
Johan Hedberg19de0822014-07-06 13:06:51 +03006186
Johan Hedberg51d7a942015-11-11 08:11:18 +02006187 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006188 }
6189
Johan Hedberg66593582014-07-09 12:59:14 +03006190complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02006191 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
6192 MGMT_STATUS_SUCCESS, &cp->addr,
6193 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006194unlock:
6195 hci_dev_unlock(hdev);
6196 return err;
6197}
6198
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006199static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6200 u16 len)
6201{
6202 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006203 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6204 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006205 u16 param_count, expected_len;
6206 int i;
6207
6208 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6210 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006211
6212 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006213 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006214 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6215 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006216 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6217 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006218 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006219
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006220 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006221 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006222 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6223 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006224 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6225 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006226 }
6227
Marcel Holtmann181d6952020-05-06 09:57:47 +02006228 bt_dev_dbg(hdev, "param_count %u", param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006229
6230 hci_dev_lock(hdev);
6231
6232 hci_conn_params_clear_disabled(hdev);
6233
6234 for (i = 0; i < param_count; i++) {
6235 struct mgmt_conn_param *param = &cp->params[i];
6236 struct hci_conn_params *hci_param;
6237 u16 min, max, latency, timeout;
6238 u8 addr_type;
6239
Marcel Holtmann181d6952020-05-06 09:57:47 +02006240 bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
6241 param->addr.type);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006242
6243 if (param->addr.type == BDADDR_LE_PUBLIC) {
6244 addr_type = ADDR_LE_DEV_PUBLIC;
6245 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6246 addr_type = ADDR_LE_DEV_RANDOM;
6247 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006248 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006249 continue;
6250 }
6251
6252 min = le16_to_cpu(param->min_interval);
6253 max = le16_to_cpu(param->max_interval);
6254 latency = le16_to_cpu(param->latency);
6255 timeout = le16_to_cpu(param->timeout);
6256
Marcel Holtmann181d6952020-05-06 09:57:47 +02006257 bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6258 min, max, latency, timeout);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006259
6260 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006261 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006262 continue;
6263 }
6264
6265 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6266 addr_type);
6267 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006268 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006269 continue;
6270 }
6271
6272 hci_param->conn_min_interval = min;
6273 hci_param->conn_max_interval = max;
6274 hci_param->conn_latency = latency;
6275 hci_param->supervision_timeout = timeout;
6276 }
6277
6278 hci_dev_unlock(hdev);
6279
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006280 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6281 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006282}
6283
Marcel Holtmanndbece372014-07-04 18:11:55 +02006284static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6285 void *data, u16 len)
6286{
6287 struct mgmt_cp_set_external_config *cp = data;
6288 bool changed;
6289 int err;
6290
Marcel Holtmann181d6952020-05-06 09:57:47 +02006291 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006292
6293 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006294 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6295 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006296
6297 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006298 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6299 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006300
6301 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006302 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6303 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006304
6305 hci_dev_lock(hdev);
6306
6307 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006308 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006309 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006310 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006311
6312 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6313 if (err < 0)
6314 goto unlock;
6315
6316 if (!changed)
6317 goto unlock;
6318
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006319 err = new_options(hdev, sk);
6320
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006321 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006322 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006323
Marcel Holtmann516018a2015-03-13 02:11:04 -07006324 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006325 hci_dev_set_flag(hdev, HCI_CONFIG);
6326 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006327
6328 queue_work(hdev->req_workqueue, &hdev->power_on);
6329 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006330 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006331 mgmt_index_added(hdev);
6332 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006333 }
6334
6335unlock:
6336 hci_dev_unlock(hdev);
6337 return err;
6338}
6339
Marcel Holtmann9713c172014-07-06 12:11:15 +02006340static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6341 void *data, u16 len)
6342{
6343 struct mgmt_cp_set_public_address *cp = data;
6344 bool changed;
6345 int err;
6346
Marcel Holtmann181d6952020-05-06 09:57:47 +02006347 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006348
6349 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006350 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6351 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006352
6353 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006354 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6355 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006356
6357 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006358 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6359 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006360
6361 hci_dev_lock(hdev);
6362
6363 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6364 bacpy(&hdev->public_addr, &cp->bdaddr);
6365
6366 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6367 if (err < 0)
6368 goto unlock;
6369
6370 if (!changed)
6371 goto unlock;
6372
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006373 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006374 err = new_options(hdev, sk);
6375
6376 if (is_configured(hdev)) {
6377 mgmt_index_removed(hdev);
6378
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006379 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006380
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006381 hci_dev_set_flag(hdev, HCI_CONFIG);
6382 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006383
6384 queue_work(hdev->req_workqueue, &hdev->power_on);
6385 }
6386
6387unlock:
6388 hci_dev_unlock(hdev);
6389 return err;
6390}
6391
Johan Hedberg40f66c02015-04-07 21:52:22 +03006392static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6393 u16 opcode, struct sk_buff *skb)
6394{
6395 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6396 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6397 u8 *h192, *r192, *h256, *r256;
6398 struct mgmt_pending_cmd *cmd;
6399 u16 eir_len;
6400 int err;
6401
Marcel Holtmann181d6952020-05-06 09:57:47 +02006402 bt_dev_dbg(hdev, "status %u", status);
Johan Hedberg40f66c02015-04-07 21:52:22 +03006403
6404 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6405 if (!cmd)
6406 return;
6407
6408 mgmt_cp = cmd->param;
6409
6410 if (status) {
6411 status = mgmt_status(status);
6412 eir_len = 0;
6413
6414 h192 = NULL;
6415 r192 = NULL;
6416 h256 = NULL;
6417 r256 = NULL;
6418 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6419 struct hci_rp_read_local_oob_data *rp;
6420
6421 if (skb->len != sizeof(*rp)) {
6422 status = MGMT_STATUS_FAILED;
6423 eir_len = 0;
6424 } else {
6425 status = MGMT_STATUS_SUCCESS;
6426 rp = (void *)skb->data;
6427
6428 eir_len = 5 + 18 + 18;
6429 h192 = rp->hash;
6430 r192 = rp->rand;
6431 h256 = NULL;
6432 r256 = NULL;
6433 }
6434 } else {
6435 struct hci_rp_read_local_oob_ext_data *rp;
6436
6437 if (skb->len != sizeof(*rp)) {
6438 status = MGMT_STATUS_FAILED;
6439 eir_len = 0;
6440 } else {
6441 status = MGMT_STATUS_SUCCESS;
6442 rp = (void *)skb->data;
6443
6444 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6445 eir_len = 5 + 18 + 18;
6446 h192 = NULL;
6447 r192 = NULL;
6448 } else {
6449 eir_len = 5 + 18 + 18 + 18 + 18;
6450 h192 = rp->hash192;
6451 r192 = rp->rand192;
6452 }
6453
6454 h256 = rp->hash256;
6455 r256 = rp->rand256;
6456 }
6457 }
6458
6459 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6460 if (!mgmt_rp)
6461 goto done;
6462
6463 if (status)
6464 goto send_rsp;
6465
6466 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6467 hdev->dev_class, 3);
6468
6469 if (h192 && r192) {
6470 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6471 EIR_SSP_HASH_C192, h192, 16);
6472 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6473 EIR_SSP_RAND_R192, r192, 16);
6474 }
6475
6476 if (h256 && r256) {
6477 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6478 EIR_SSP_HASH_C256, h256, 16);
6479 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6480 EIR_SSP_RAND_R256, r256, 16);
6481 }
6482
6483send_rsp:
6484 mgmt_rp->type = mgmt_cp->type;
6485 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6486
6487 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6488 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6489 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6490 if (err < 0 || status)
6491 goto done;
6492
6493 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6494
6495 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6496 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6497 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6498done:
6499 kfree(mgmt_rp);
6500 mgmt_pending_remove(cmd);
6501}
6502
6503static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6504 struct mgmt_cp_read_local_oob_ext_data *cp)
6505{
6506 struct mgmt_pending_cmd *cmd;
6507 struct hci_request req;
6508 int err;
6509
6510 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6511 cp, sizeof(*cp));
6512 if (!cmd)
6513 return -ENOMEM;
6514
6515 hci_req_init(&req, hdev);
6516
6517 if (bredr_sc_enabled(hdev))
6518 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6519 else
6520 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6521
6522 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6523 if (err < 0) {
6524 mgmt_pending_remove(cmd);
6525 return err;
6526 }
6527
6528 return 0;
6529}
6530
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006531static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6532 void *data, u16 data_len)
6533{
6534 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6535 struct mgmt_rp_read_local_oob_ext_data *rp;
6536 size_t rp_len;
6537 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006538 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006539 int err;
6540
Marcel Holtmann181d6952020-05-06 09:57:47 +02006541 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006542
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006543 if (hdev_is_powered(hdev)) {
6544 switch (cp->type) {
6545 case BIT(BDADDR_BREDR):
6546 status = mgmt_bredr_support(hdev);
6547 if (status)
6548 eir_len = 0;
6549 else
6550 eir_len = 5;
6551 break;
6552 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6553 status = mgmt_le_support(hdev);
6554 if (status)
6555 eir_len = 0;
6556 else
6557 eir_len = 9 + 3 + 18 + 18 + 3;
6558 break;
6559 default:
6560 status = MGMT_STATUS_INVALID_PARAMS;
6561 eir_len = 0;
6562 break;
6563 }
6564 } else {
6565 status = MGMT_STATUS_NOT_POWERED;
6566 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006567 }
6568
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006569 rp_len = sizeof(*rp) + eir_len;
6570 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006571 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006572 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006573
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006574 if (status)
6575 goto complete;
6576
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006577 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006578
6579 eir_len = 0;
6580 switch (cp->type) {
6581 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006582 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6583 err = read_local_ssp_oob_req(hdev, sk, cp);
6584 hci_dev_unlock(hdev);
6585 if (!err)
6586 goto done;
6587
6588 status = MGMT_STATUS_FAILED;
6589 goto complete;
6590 } else {
6591 eir_len = eir_append_data(rp->eir, eir_len,
6592 EIR_CLASS_OF_DEV,
6593 hdev->dev_class, 3);
6594 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006595 break;
6596 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006597 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6598 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006599 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006600 status = MGMT_STATUS_FAILED;
6601 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006602 }
6603
Marcel Holtmanne2135682015-04-02 12:00:58 -07006604 /* This should return the active RPA, but since the RPA
6605 * is only programmed on demand, it is really hard to fill
6606 * this in at the moment. For now disallow retrieving
6607 * local out-of-band data when privacy is in use.
6608 *
6609 * Returning the identity address will not help here since
6610 * pairing happens before the identity resolving key is
6611 * known and thus the connection establishment happens
6612 * based on the RPA and not the identity address.
6613 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006614 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006615 hci_dev_unlock(hdev);
6616 status = MGMT_STATUS_REJECTED;
6617 goto complete;
6618 }
6619
6620 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6621 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6622 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6623 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006624 memcpy(addr, &hdev->static_addr, 6);
6625 addr[6] = 0x01;
6626 } else {
6627 memcpy(addr, &hdev->bdaddr, 6);
6628 addr[6] = 0x00;
6629 }
6630
6631 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6632 addr, sizeof(addr));
6633
6634 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6635 role = 0x02;
6636 else
6637 role = 0x01;
6638
6639 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6640 &role, sizeof(role));
6641
Marcel Holtmann5082a592015-03-16 12:39:00 -07006642 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6643 eir_len = eir_append_data(rp->eir, eir_len,
6644 EIR_LE_SC_CONFIRM,
6645 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006646
Marcel Holtmann5082a592015-03-16 12:39:00 -07006647 eir_len = eir_append_data(rp->eir, eir_len,
6648 EIR_LE_SC_RANDOM,
6649 rand, sizeof(rand));
6650 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006651
Johan Hedbergf2252572015-11-18 12:49:20 +02006652 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006653
6654 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6655 flags |= LE_AD_NO_BREDR;
6656
6657 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6658 &flags, sizeof(flags));
6659 break;
6660 }
6661
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006662 hci_dev_unlock(hdev);
6663
Marcel Holtmann72000df2015-03-16 16:11:21 -07006664 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6665
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006666 status = MGMT_STATUS_SUCCESS;
6667
6668complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006669 rp->type = cp->type;
6670 rp->eir_len = cpu_to_le16(eir_len);
6671
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006672 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006673 status, rp, sizeof(*rp) + eir_len);
6674 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006675 goto done;
6676
6677 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6678 rp, sizeof(*rp) + eir_len,
6679 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006680
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006681done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006682 kfree(rp);
6683
6684 return err;
6685}
6686
Arman Uguray089fa8c2015-03-25 18:53:45 -07006687static u32 get_supported_adv_flags(struct hci_dev *hdev)
6688{
6689 u32 flags = 0;
6690
6691 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6692 flags |= MGMT_ADV_FLAG_DISCOV;
6693 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6694 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006695 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006696 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006697
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306698 /* In extended adv TX_POWER returned from Set Adv Param
6699 * will be always valid.
6700 */
6701 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6702 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006703 flags |= MGMT_ADV_FLAG_TX_POWER;
6704
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306705 if (ext_adv_capable(hdev)) {
6706 flags |= MGMT_ADV_FLAG_SEC_1M;
6707
6708 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6709 flags |= MGMT_ADV_FLAG_SEC_2M;
6710
6711 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6712 flags |= MGMT_ADV_FLAG_SEC_CODED;
6713 }
6714
Arman Uguray089fa8c2015-03-25 18:53:45 -07006715 return flags;
6716}
6717
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006718static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6719 void *data, u16 data_len)
6720{
6721 struct mgmt_rp_read_adv_features *rp;
6722 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006723 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006724 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006725 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006726 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006727
Marcel Holtmann181d6952020-05-06 09:57:47 +02006728 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006729
Arman Uguray089fa8c2015-03-25 18:53:45 -07006730 if (!lmp_le_capable(hdev))
6731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6732 MGMT_STATUS_REJECTED);
6733
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006734 hci_dev_lock(hdev);
6735
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006736 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006737 rp = kmalloc(rp_len, GFP_ATOMIC);
6738 if (!rp) {
6739 hci_dev_unlock(hdev);
6740 return -ENOMEM;
6741 }
6742
Arman Uguray089fa8c2015-03-25 18:53:45 -07006743 supported_flags = get_supported_adv_flags(hdev);
6744
6745 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006746 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6747 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006748 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006749 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006750
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006751 instance = rp->instance;
6752 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6753 *instance = adv_instance->instance;
6754 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006755 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006756
6757 hci_dev_unlock(hdev);
6758
6759 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6760 MGMT_STATUS_SUCCESS, rp, rp_len);
6761
6762 kfree(rp);
6763
6764 return err;
6765}
6766
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006767static u8 calculate_name_len(struct hci_dev *hdev)
6768{
6769 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6770
6771 return append_local_name(hdev, buf, 0);
6772}
6773
6774static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6775 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006776{
Arman Uguray4117ed72015-03-23 15:57:14 -07006777 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006778
Marcel Holtmann31a32482015-11-19 16:16:42 +01006779 if (is_adv_data) {
6780 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6781 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006782 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006783 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006784
Szymon Janc2bb368702016-09-18 12:50:05 +02006785 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006786 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006787 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006788 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006789 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006790
Szymon Janc2bb368702016-09-18 12:50:05 +02006791 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006792 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006793 }
6794
Szymon Janc2bb368702016-09-18 12:50:05 +02006795 return max_len;
6796}
6797
6798static bool flags_managed(u32 adv_flags)
6799{
6800 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6801 MGMT_ADV_FLAG_LIMITED_DISCOV |
6802 MGMT_ADV_FLAG_MANAGED_FLAGS);
6803}
6804
6805static bool tx_power_managed(u32 adv_flags)
6806{
6807 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6808}
6809
6810static bool name_managed(u32 adv_flags)
6811{
6812 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6813}
6814
6815static bool appearance_managed(u32 adv_flags)
6816{
6817 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6818}
6819
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006820static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6821 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006822{
6823 int i, cur_len;
6824 u8 max_len;
6825
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006826 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006827
Arman Uguray4117ed72015-03-23 15:57:14 -07006828 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006829 return false;
6830
Arman Uguray4117ed72015-03-23 15:57:14 -07006831 /* Make sure that the data is correctly formatted. */
6832 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6833 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006834
Szymon Janc9c9db782016-09-18 12:50:06 +02006835 if (data[i + 1] == EIR_FLAGS &&
6836 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006837 return false;
6838
Szymon Janc2bb368702016-09-18 12:50:05 +02006839 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6840 return false;
6841
6842 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6843 return false;
6844
6845 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6846 return false;
6847
6848 if (data[i + 1] == EIR_APPEARANCE &&
6849 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006850 return false;
6851
Arman Uguray24b4f382015-03-23 15:57:12 -07006852 /* If the current field length would exceed the total data
6853 * length, then it's invalid.
6854 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006855 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006856 return false;
6857 }
6858
6859 return true;
6860}
6861
Arman Uguray24b4f382015-03-23 15:57:12 -07006862static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6863 u16 opcode)
6864{
6865 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006866 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006867 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006868 struct adv_info *adv_instance, *n;
6869 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006870
Marcel Holtmann181d6952020-05-06 09:57:47 +02006871 bt_dev_dbg(hdev, "status %d", status);
Arman Uguray24b4f382015-03-23 15:57:12 -07006872
6873 hci_dev_lock(hdev);
6874
6875 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6876
Florian Grandelfffd38b2015-06-18 03:16:47 +02006877 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6878 if (!adv_instance->pending)
6879 continue;
6880
6881 if (!status) {
6882 adv_instance->pending = false;
6883 continue;
6884 }
6885
6886 instance = adv_instance->instance;
6887
6888 if (hdev->cur_adv_instance == instance)
6889 cancel_adv_timeout(hdev);
6890
6891 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006892 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006893 }
6894
6895 if (!cmd)
6896 goto unlock;
6897
Florian Grandelfffd38b2015-06-18 03:16:47 +02006898 cp = cmd->param;
6899 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006900
6901 if (status)
6902 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6903 mgmt_status(status));
6904 else
6905 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6906 mgmt_status(status), &rp, sizeof(rp));
6907
6908 mgmt_pending_remove(cmd);
6909
6910unlock:
6911 hci_dev_unlock(hdev);
6912}
6913
6914static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6915 void *data, u16 data_len)
6916{
6917 struct mgmt_cp_add_advertising *cp = data;
6918 struct mgmt_rp_add_advertising rp;
6919 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306920 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006921 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006922 u16 timeout, duration;
6923 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6924 u8 schedule_instance = 0;
6925 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006926 int err;
6927 struct mgmt_pending_cmd *cmd;
6928 struct hci_request req;
6929
Marcel Holtmann181d6952020-05-06 09:57:47 +02006930 bt_dev_dbg(hdev, "sock %p", sk);
Arman Uguray24b4f382015-03-23 15:57:12 -07006931
6932 status = mgmt_le_support(hdev);
6933 if (status)
6934 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6935 status);
6936
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006937 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6938 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6939 MGMT_STATUS_INVALID_PARAMS);
6940
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006941 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6942 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6943 MGMT_STATUS_INVALID_PARAMS);
6944
Arman Uguray24b4f382015-03-23 15:57:12 -07006945 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006946 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006947 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006948
Florian Grandelfffd38b2015-06-18 03:16:47 +02006949 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306950 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006951 */
6952 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306953 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
6954 if (flags & ~supported_flags ||
6955 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07006956 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6957 MGMT_STATUS_INVALID_PARAMS);
6958
6959 hci_dev_lock(hdev);
6960
Arman Uguray912098a2015-03-23 15:57:15 -07006961 if (timeout && !hdev_is_powered(hdev)) {
6962 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6963 MGMT_STATUS_REJECTED);
6964 goto unlock;
6965 }
6966
Arman Uguray24b4f382015-03-23 15:57:12 -07006967 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006968 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006969 pending_find(MGMT_OP_SET_LE, hdev)) {
6970 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6971 MGMT_STATUS_BUSY);
6972 goto unlock;
6973 }
6974
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006975 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6976 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006977 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006978 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6979 MGMT_STATUS_INVALID_PARAMS);
6980 goto unlock;
6981 }
6982
Florian Grandelfffd38b2015-06-18 03:16:47 +02006983 err = hci_add_adv_instance(hdev, cp->instance, flags,
6984 cp->adv_data_len, cp->data,
6985 cp->scan_rsp_len,
6986 cp->data + cp->adv_data_len,
6987 timeout, duration);
6988 if (err < 0) {
6989 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6990 MGMT_STATUS_FAILED);
6991 goto unlock;
6992 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006993
Florian Grandelfffd38b2015-06-18 03:16:47 +02006994 /* Only trigger an advertising added event if a new instance was
6995 * actually added.
6996 */
6997 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006998 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006999
Florian Grandelfffd38b2015-06-18 03:16:47 +02007000 if (hdev->cur_adv_instance == cp->instance) {
7001 /* If the currently advertised instance is being changed then
7002 * cancel the current advertising and schedule the next
7003 * instance. If there is only one instance then the overridden
7004 * advertising data will be visible right away.
7005 */
7006 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007007
Florian Grandelfffd38b2015-06-18 03:16:47 +02007008 next_instance = hci_get_next_instance(hdev, cp->instance);
7009 if (next_instance)
7010 schedule_instance = next_instance->instance;
7011 } else if (!hdev->adv_instance_timeout) {
7012 /* Immediately advertise the new instance if no other
7013 * instance is currently being advertised.
7014 */
7015 schedule_instance = cp->instance;
7016 }
Arman Uguray912098a2015-03-23 15:57:15 -07007017
Florian Grandelfffd38b2015-06-18 03:16:47 +02007018 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
7019 * there is no instance to be advertised then we have no HCI
7020 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07007021 */
7022 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02007023 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7024 !schedule_instance) {
7025 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07007026 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7027 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7028 goto unlock;
7029 }
7030
7031 /* We're good to go, update advertising data, parameters, and start
7032 * advertising.
7033 */
7034 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7035 data_len);
7036 if (!cmd) {
7037 err = -ENOMEM;
7038 goto unlock;
7039 }
7040
7041 hci_req_init(&req, hdev);
7042
Johan Hedbergf2252572015-11-18 12:49:20 +02007043 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07007044
Florian Grandelfffd38b2015-06-18 03:16:47 +02007045 if (!err)
7046 err = hci_req_run(&req, add_advertising_complete);
7047
Joseph Hwang72da7b22020-03-10 09:31:50 -07007048 if (err < 0) {
7049 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7050 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07007051 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07007052 }
Arman Uguray24b4f382015-03-23 15:57:12 -07007053
7054unlock:
7055 hci_dev_unlock(hdev);
7056
7057 return err;
7058}
7059
Arman Ugurayda9293352015-03-23 15:57:13 -07007060static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7061 u16 opcode)
7062{
7063 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02007064 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007065 struct mgmt_rp_remove_advertising rp;
7066
Marcel Holtmann181d6952020-05-06 09:57:47 +02007067 bt_dev_dbg(hdev, "status %d", status);
Arman Ugurayda9293352015-03-23 15:57:13 -07007068
7069 hci_dev_lock(hdev);
7070
7071 /* A failure status here only means that we failed to disable
7072 * advertising. Otherwise, the advertising instance has been removed,
7073 * so report success.
7074 */
7075 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7076 if (!cmd)
7077 goto unlock;
7078
Florian Grandel01948332015-06-18 03:16:48 +02007079 cp = cmd->param;
7080 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007081
7082 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7083 &rp, sizeof(rp));
7084 mgmt_pending_remove(cmd);
7085
7086unlock:
7087 hci_dev_unlock(hdev);
7088}
7089
7090static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7091 void *data, u16 data_len)
7092{
7093 struct mgmt_cp_remove_advertising *cp = data;
7094 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07007095 struct mgmt_pending_cmd *cmd;
7096 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03007097 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07007098
Marcel Holtmann181d6952020-05-06 09:57:47 +02007099 bt_dev_dbg(hdev, "sock %p", sk);
Arman Ugurayda9293352015-03-23 15:57:13 -07007100
Arman Ugurayda9293352015-03-23 15:57:13 -07007101 hci_dev_lock(hdev);
7102
Johan Hedberg952497b2015-06-18 21:05:31 +03007103 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02007104 err = mgmt_cmd_status(sk, hdev->id,
7105 MGMT_OP_REMOVE_ADVERTISING,
7106 MGMT_STATUS_INVALID_PARAMS);
7107 goto unlock;
7108 }
7109
Arman Ugurayda9293352015-03-23 15:57:13 -07007110 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7111 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7112 pending_find(MGMT_OP_SET_LE, hdev)) {
7113 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7114 MGMT_STATUS_BUSY);
7115 goto unlock;
7116 }
7117
Johan Hedberg17fd08f2015-11-26 12:15:59 +02007118 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07007119 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7120 MGMT_STATUS_INVALID_PARAMS);
7121 goto unlock;
7122 }
7123
Florian Grandel01948332015-06-18 03:16:48 +02007124 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07007125
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03007126 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07007127
Florian Grandel01948332015-06-18 03:16:48 +02007128 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02007129 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07007130
Florian Grandel01948332015-06-18 03:16:48 +02007131 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7132 * flag is set or the device isn't powered then we have no HCI
7133 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07007134 */
Florian Grandel01948332015-06-18 03:16:48 +02007135 if (skb_queue_empty(&req.cmd_q) ||
7136 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07007137 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05307138 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02007139 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07007140 err = mgmt_cmd_complete(sk, hdev->id,
7141 MGMT_OP_REMOVE_ADVERTISING,
7142 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7143 goto unlock;
7144 }
7145
7146 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7147 data_len);
7148 if (!cmd) {
7149 err = -ENOMEM;
7150 goto unlock;
7151 }
7152
Arman Ugurayda9293352015-03-23 15:57:13 -07007153 err = hci_req_run(&req, remove_advertising_complete);
7154 if (err < 0)
7155 mgmt_pending_remove(cmd);
7156
7157unlock:
7158 hci_dev_unlock(hdev);
7159
7160 return err;
7161}
7162
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007163static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7164 void *data, u16 data_len)
7165{
7166 struct mgmt_cp_get_adv_size_info *cp = data;
7167 struct mgmt_rp_get_adv_size_info rp;
7168 u32 flags, supported_flags;
7169 int err;
7170
Marcel Holtmann181d6952020-05-06 09:57:47 +02007171 bt_dev_dbg(hdev, "sock %p", sk);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007172
7173 if (!lmp_le_capable(hdev))
7174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7175 MGMT_STATUS_REJECTED);
7176
7177 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7178 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7179 MGMT_STATUS_INVALID_PARAMS);
7180
7181 flags = __le32_to_cpu(cp->flags);
7182
7183 /* The current implementation only supports a subset of the specified
7184 * flags.
7185 */
7186 supported_flags = get_supported_adv_flags(hdev);
7187 if (flags & ~supported_flags)
7188 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7189 MGMT_STATUS_INVALID_PARAMS);
7190
7191 rp.instance = cp->instance;
7192 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02007193 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
7194 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007195
7196 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7197 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7198
7199 return err;
7200}
7201
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007202static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007203 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007204 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007205 HCI_MGMT_NO_HDEV |
7206 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007207 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007208 HCI_MGMT_NO_HDEV |
7209 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007210 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007211 HCI_MGMT_NO_HDEV |
7212 HCI_MGMT_UNTRUSTED },
7213 { read_controller_info, MGMT_READ_INFO_SIZE,
7214 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007215 { set_powered, MGMT_SETTING_SIZE },
7216 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7217 { set_connectable, MGMT_SETTING_SIZE },
7218 { set_fast_connectable, MGMT_SETTING_SIZE },
7219 { set_bondable, MGMT_SETTING_SIZE },
7220 { set_link_security, MGMT_SETTING_SIZE },
7221 { set_ssp, MGMT_SETTING_SIZE },
7222 { set_hs, MGMT_SETTING_SIZE },
7223 { set_le, MGMT_SETTING_SIZE },
7224 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7225 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7226 { add_uuid, MGMT_ADD_UUID_SIZE },
7227 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007228 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7229 HCI_MGMT_VAR_LEN },
7230 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7231 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007232 { disconnect, MGMT_DISCONNECT_SIZE },
7233 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7234 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7235 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7236 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7237 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7238 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7239 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7240 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7241 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7242 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7243 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007244 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7245 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7246 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007247 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7248 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7249 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7250 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7251 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7252 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7253 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7254 { set_advertising, MGMT_SETTING_SIZE },
7255 { set_bredr, MGMT_SETTING_SIZE },
7256 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7257 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7258 { set_secure_conn, MGMT_SETTING_SIZE },
7259 { set_debug_keys, MGMT_SETTING_SIZE },
7260 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007261 { load_irks, MGMT_LOAD_IRKS_SIZE,
7262 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007263 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7264 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7265 { add_device, MGMT_ADD_DEVICE_SIZE },
7266 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007267 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7268 HCI_MGMT_VAR_LEN },
7269 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007270 HCI_MGMT_NO_HDEV |
7271 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007272 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007273 HCI_MGMT_UNCONFIGURED |
7274 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007275 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7276 HCI_MGMT_UNCONFIGURED },
7277 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7278 HCI_MGMT_UNCONFIGURED },
7279 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7280 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007281 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007282 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007283 HCI_MGMT_NO_HDEV |
7284 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007285 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007286 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7287 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007288 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007289 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007290 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007291 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7292 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007293 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307294 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307295 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007296 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7297 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007298 { set_wideband_speech, MGMT_SETTING_SIZE },
Marcel Holtmannbc292252020-04-03 21:44:05 +02007299 { read_security_info, MGMT_READ_SECURITY_INFO_SIZE,
7300 HCI_MGMT_UNTRUSTED },
Marcel Holtmanna10c9072020-05-06 09:57:51 +02007301 { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE,
7302 HCI_MGMT_UNTRUSTED |
7303 HCI_MGMT_HDEV_OPTIONAL },
7304 { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE,
7305 HCI_MGMT_VAR_LEN |
7306 HCI_MGMT_HDEV_OPTIONAL },
Alain Michaud17896402020-06-11 02:01:57 +00007307 { read_def_system_config, MGMT_READ_DEF_SYSTEM_CONFIG_SIZE,
7308 HCI_MGMT_UNTRUSTED },
7309 { set_def_system_config, MGMT_SET_DEF_SYSTEM_CONFIG_SIZE,
7310 HCI_MGMT_VAR_LEN },
Marcel Holtmannaececa62020-06-17 16:39:07 +02007311 { read_def_runtime_config, MGMT_READ_DEF_RUNTIME_CONFIG_SIZE,
7312 HCI_MGMT_UNTRUSTED },
7313 { set_def_runtime_config, MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
7314 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007315};
7316
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007317void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007318{
Marcel Holtmannced85542015-03-14 19:27:56 -07007319 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007320
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007321 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7322 return;
7323
Marcel Holtmannf9207332015-03-14 19:27:55 -07007324 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007325 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007326 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7327 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7328 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007329 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007330 } else {
7331 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7332 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007333 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007334 }
7335 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007336 case HCI_AMP:
7337 ev.type = 0x02;
7338 break;
7339 default:
7340 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007341 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007342
7343 ev.bus = hdev->bus;
7344
7345 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7346 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007347}
7348
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007349void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007350{
Marcel Holtmannced85542015-03-14 19:27:56 -07007351 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007352 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007353
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007354 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7355 return;
7356
Marcel Holtmannf9207332015-03-14 19:27:55 -07007357 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007358 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007359 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007360
Marcel Holtmannf9207332015-03-14 19:27:55 -07007361 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7362 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7363 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007364 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007365 } else {
7366 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7367 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007368 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007369 }
7370 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007371 case HCI_AMP:
7372 ev.type = 0x02;
7373 break;
7374 default:
7375 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007376 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007377
7378 ev.bus = hdev->bus;
7379
7380 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7381 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007382}
7383
Andre Guedes6046dc32014-02-26 20:21:51 -03007384/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007385static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007386{
7387 struct hci_conn_params *p;
7388
7389 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007390 /* Needed for AUTO_OFF case where might not "really"
7391 * have been powered off.
7392 */
7393 list_del_init(&p->action);
7394
7395 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007396 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007397 case HCI_AUTO_CONN_ALWAYS:
7398 list_add(&p->action, &hdev->pend_le_conns);
7399 break;
7400 case HCI_AUTO_CONN_REPORT:
7401 list_add(&p->action, &hdev->pend_le_reports);
7402 break;
7403 default:
7404 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007405 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007406 }
7407}
7408
Johan Hedberg2ff13892015-11-25 16:15:44 +02007409void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007410{
7411 struct cmd_lookup match = { NULL, hdev };
7412
Marcel Holtmann181d6952020-05-06 09:57:47 +02007413 bt_dev_dbg(hdev, "err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007414
Johan Hedberg2ff13892015-11-25 16:15:44 +02007415 hci_dev_lock(hdev);
7416
7417 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007418 restart_le_actions(hdev);
7419 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007420 }
7421
Johan Hedberg229ab392013-03-15 17:06:53 -05007422 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7423
7424 new_settings(hdev, match.sk);
7425
Johan Hedberg229ab392013-03-15 17:06:53 -05007426 if (match.sk)
7427 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007428
7429 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007430}
7431
Johan Hedberg2ff13892015-11-25 16:15:44 +02007432void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007433{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007434 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007435 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007436
Johan Hedberg229ab392013-03-15 17:06:53 -05007437 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007438
7439 /* If the power off is because of hdev unregistration let
7440 * use the appropriate INVALID_INDEX status. Otherwise use
7441 * NOT_POWERED. We cover both scenarios here since later in
7442 * mgmt_index_removed() any hci_conn callbacks will have already
7443 * been triggered, potentially causing misleading DISCONNECTED
7444 * status responses.
7445 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007446 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007447 status = MGMT_STATUS_INVALID_INDEX;
7448 else
7449 status = MGMT_STATUS_NOT_POWERED;
7450
7451 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007452
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007453 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007454 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7455 zero_cod, sizeof(zero_cod),
7456 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007457 ext_info_changed(hdev, NULL);
7458 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007459
Johan Hedberg2ff13892015-11-25 16:15:44 +02007460 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007461
7462 if (match.sk)
7463 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007464}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007465
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007466void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007467{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007468 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007469 u8 status;
7470
Johan Hedberg333ae952015-03-17 13:48:47 +02007471 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007472 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007473 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007474
7475 if (err == -ERFKILL)
7476 status = MGMT_STATUS_RFKILLED;
7477 else
7478 status = MGMT_STATUS_FAILED;
7479
Johan Hedberga69e8372015-03-06 21:08:53 +02007480 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007481
7482 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007483}
7484
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007485void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7486 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007487{
Johan Hedberg86742e12011-11-07 23:13:38 +02007488 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007489
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007490 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007491
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007492 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007493 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007494 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007495 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007496 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007497 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007498
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007499 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007500}
Johan Hedbergf7520542011-01-20 12:34:39 +02007501
Johan Hedbergd7b25452014-05-23 13:19:53 +03007502static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7503{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007504 switch (ltk->type) {
7505 case SMP_LTK:
7506 case SMP_LTK_SLAVE:
7507 if (ltk->authenticated)
7508 return MGMT_LTK_AUTHENTICATED;
7509 return MGMT_LTK_UNAUTHENTICATED;
7510 case SMP_LTK_P256:
7511 if (ltk->authenticated)
7512 return MGMT_LTK_P256_AUTH;
7513 return MGMT_LTK_P256_UNAUTH;
7514 case SMP_LTK_P256_DEBUG:
7515 return MGMT_LTK_P256_DEBUG;
7516 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007517
7518 return MGMT_LTK_UNAUTHENTICATED;
7519}
7520
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007521void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007522{
7523 struct mgmt_ev_new_long_term_key ev;
7524
7525 memset(&ev, 0, sizeof(ev));
7526
Marcel Holtmann5192d302014-02-19 17:11:58 -08007527 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007528 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007529 * to store long term keys. Their addresses will change the
7530 * next time around.
7531 *
7532 * Only when a remote device provides an identity address
7533 * make sure the long term key is stored. If the remote
7534 * identity is known, the long term keys are internally
7535 * mapped to the identity address. So allow static random
7536 * and public addresses here.
7537 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007538 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7539 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7540 ev.store_hint = 0x00;
7541 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007542 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007543
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007544 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007545 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007546 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007547 ev.key.enc_size = key->enc_size;
7548 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007549 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007550
Johan Hedberg2ceba532014-06-16 19:25:16 +03007551 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007552 ev.key.master = 1;
7553
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007554 /* Make sure we copy only the significant bytes based on the
7555 * encryption key size, and set the rest of the value to zeroes.
7556 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007557 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007558 memset(ev.key.val + key->enc_size, 0,
7559 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007560
Marcel Holtmann083368f2013-10-15 14:26:29 -07007561 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007562}
7563
Johan Hedbergcad20c22015-10-12 13:36:19 +02007564void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007565{
7566 struct mgmt_ev_new_irk ev;
7567
7568 memset(&ev, 0, sizeof(ev));
7569
Johan Hedbergcad20c22015-10-12 13:36:19 +02007570 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007571
Johan Hedberg95fbac82014-02-19 15:18:31 +02007572 bacpy(&ev.rpa, &irk->rpa);
7573 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7574 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7575 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7576
7577 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7578}
7579
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007580void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7581 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007582{
7583 struct mgmt_ev_new_csrk ev;
7584
7585 memset(&ev, 0, sizeof(ev));
7586
7587 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007588 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007589 * to store signature resolving keys. Their addresses will change
7590 * the next time around.
7591 *
7592 * Only when a remote device provides an identity address
7593 * make sure the signature resolving key is stored. So allow
7594 * static random and public addresses here.
7595 */
7596 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7597 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7598 ev.store_hint = 0x00;
7599 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007600 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007601
7602 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7603 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007604 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007605 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7606
7607 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7608}
7609
Andre Guedesffb5a8272014-07-01 18:10:11 -03007610void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007611 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7612 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007613{
7614 struct mgmt_ev_new_conn_param ev;
7615
Johan Hedbergc103aea2014-07-02 17:37:34 +03007616 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7617 return;
7618
Andre Guedesffb5a8272014-07-01 18:10:11 -03007619 memset(&ev, 0, sizeof(ev));
7620 bacpy(&ev.addr.bdaddr, bdaddr);
7621 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007622 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007623 ev.min_interval = cpu_to_le16(min_interval);
7624 ev.max_interval = cpu_to_le16(max_interval);
7625 ev.latency = cpu_to_le16(latency);
7626 ev.timeout = cpu_to_le16(timeout);
7627
7628 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7629}
7630
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007631void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7632 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007633{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007634 char buf[512];
7635 struct mgmt_ev_device_connected *ev = (void *) buf;
7636 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007637
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007638 bacpy(&ev->addr.bdaddr, &conn->dst);
7639 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007640
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007641 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007642
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007643 /* We must ensure that the EIR Data fields are ordered and
7644 * unique. Keep it simple for now and avoid the problem by not
7645 * adding any BR/EDR data to the LE adv.
7646 */
7647 if (conn->le_adv_data_len > 0) {
7648 memcpy(&ev->eir[eir_len],
7649 conn->le_adv_data, conn->le_adv_data_len);
7650 eir_len = conn->le_adv_data_len;
7651 } else {
7652 if (name_len > 0)
7653 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7654 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007655
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007656 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007657 eir_len = eir_append_data(ev->eir, eir_len,
7658 EIR_CLASS_OF_DEV,
7659 conn->dev_class, 3);
7660 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007661
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007662 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007663
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007664 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7665 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007666}
7667
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007668static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007669{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007670 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007671
Johan Hedbergf5818c22014-12-05 13:36:02 +02007672 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007673
7674 *sk = cmd->sk;
7675 sock_hold(*sk);
7676
Johan Hedberga664b5b2011-02-19 12:06:02 -03007677 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007678}
7679
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007680static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007681{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007682 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007683 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007684
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007685 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7686
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007687 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007688 mgmt_pending_remove(cmd);
7689}
7690
Johan Hedberg84c61d92014-08-01 11:13:30 +03007691bool mgmt_powering_down(struct hci_dev *hdev)
7692{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007693 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007694 struct mgmt_mode *cp;
7695
Johan Hedberg333ae952015-03-17 13:48:47 +02007696 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007697 if (!cmd)
7698 return false;
7699
7700 cp = cmd->param;
7701 if (!cp->val)
7702 return true;
7703
7704 return false;
7705}
7706
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007707void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007708 u8 link_type, u8 addr_type, u8 reason,
7709 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007710{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007711 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007712 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007713
Johan Hedberg84c61d92014-08-01 11:13:30 +03007714 /* The connection is still in hci_conn_hash so test for 1
7715 * instead of 0 to know if this is the last one.
7716 */
7717 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7718 cancel_delayed_work(&hdev->power_off);
7719 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007720 }
7721
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007722 if (!mgmt_connected)
7723 return;
7724
Andre Guedes57eb7762013-10-30 19:01:41 -03007725 if (link_type != ACL_LINK && link_type != LE_LINK)
7726 return;
7727
Johan Hedberg744cf192011-11-08 20:40:14 +02007728 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007729
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007730 bacpy(&ev.addr.bdaddr, bdaddr);
7731 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7732 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007733
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007734 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007735
7736 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007737 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007738
Johan Hedberg124f6e32012-02-09 13:50:12 +02007739 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007740 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007741}
7742
Marcel Holtmann78929242013-10-06 23:55:47 -07007743void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7744 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007745{
Andre Guedes3655bba2013-10-30 19:01:40 -03007746 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7747 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007748 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007749
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007750 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7751 hdev);
7752
Johan Hedberg333ae952015-03-17 13:48:47 +02007753 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007754 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007755 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007756
Andre Guedes3655bba2013-10-30 19:01:40 -03007757 cp = cmd->param;
7758
7759 if (bacmp(bdaddr, &cp->addr.bdaddr))
7760 return;
7761
7762 if (cp->addr.type != bdaddr_type)
7763 return;
7764
Johan Hedbergf5818c22014-12-05 13:36:02 +02007765 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007766 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007767}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007768
Marcel Holtmann445608d2013-10-06 23:55:48 -07007769void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7770 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007771{
7772 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007773
Johan Hedberg84c61d92014-08-01 11:13:30 +03007774 /* The connection is still in hci_conn_hash so test for 1
7775 * instead of 0 to know if this is the last one.
7776 */
7777 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7778 cancel_delayed_work(&hdev->power_off);
7779 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007780 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007781
Johan Hedberg4c659c32011-11-07 23:13:39 +02007782 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007783 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007784 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007785
Marcel Holtmann445608d2013-10-06 23:55:48 -07007786 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007787}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007788
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007789void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007790{
7791 struct mgmt_ev_pin_code_request ev;
7792
Johan Hedbergd8457692012-02-17 14:24:57 +02007793 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007794 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007795 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007796
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007797 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007798}
7799
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007800void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7801 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007802{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007803 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007804
Johan Hedberg333ae952015-03-17 13:48:47 +02007805 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007806 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007807 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007808
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007809 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007810 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007811}
7812
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007813void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7814 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007815{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007816 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007817
Johan Hedberg333ae952015-03-17 13:48:47 +02007818 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007819 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007820 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007821
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007822 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007823 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007824}
Johan Hedberga5c29682011-02-19 12:05:57 -03007825
Johan Hedberg744cf192011-11-08 20:40:14 +02007826int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007827 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007828 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007829{
7830 struct mgmt_ev_user_confirm_request ev;
7831
Marcel Holtmann181d6952020-05-06 09:57:47 +02007832 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03007833
Johan Hedberg272d90d2012-02-09 15:26:12 +02007834 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007835 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007836 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007837 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007838
Johan Hedberg744cf192011-11-08 20:40:14 +02007839 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007840 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007841}
7842
Johan Hedberg272d90d2012-02-09 15:26:12 +02007843int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007844 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007845{
7846 struct mgmt_ev_user_passkey_request ev;
7847
Marcel Holtmann181d6952020-05-06 09:57:47 +02007848 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08007849
Johan Hedberg272d90d2012-02-09 15:26:12 +02007850 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007851 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007852
7853 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007854 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007855}
7856
Brian Gix0df4c182011-11-16 13:53:13 -08007857static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007858 u8 link_type, u8 addr_type, u8 status,
7859 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007860{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007861 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007862
Johan Hedberg333ae952015-03-17 13:48:47 +02007863 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007864 if (!cmd)
7865 return -ENOENT;
7866
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007867 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007868 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007869
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007870 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007871}
7872
Johan Hedberg744cf192011-11-08 20:40:14 +02007873int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007874 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007875{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007876 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007877 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007878}
7879
Johan Hedberg272d90d2012-02-09 15:26:12 +02007880int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007881 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007882{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007883 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007884 status,
7885 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007886}
Johan Hedberg2a611692011-02-19 12:06:00 -03007887
Brian Gix604086b2011-11-23 08:28:33 -08007888int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007889 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007890{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007891 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007892 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007893}
7894
Johan Hedberg272d90d2012-02-09 15:26:12 +02007895int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007896 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007897{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007898 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007899 status,
7900 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007901}
7902
Johan Hedberg92a25252012-09-06 18:39:26 +03007903int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7904 u8 link_type, u8 addr_type, u32 passkey,
7905 u8 entered)
7906{
7907 struct mgmt_ev_passkey_notify ev;
7908
Marcel Holtmann181d6952020-05-06 09:57:47 +02007909 bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
Johan Hedberg92a25252012-09-06 18:39:26 +03007910
7911 bacpy(&ev.addr.bdaddr, bdaddr);
7912 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7913 ev.passkey = __cpu_to_le32(passkey);
7914 ev.entered = entered;
7915
7916 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7917}
7918
Johan Hedberge1e930f2014-09-08 17:09:49 -07007919void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007920{
7921 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007922 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007923 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007924
Johan Hedberge1e930f2014-09-08 17:09:49 -07007925 bacpy(&ev.addr.bdaddr, &conn->dst);
7926 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7927 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007928
Johan Hedberge1e930f2014-09-08 17:09:49 -07007929 cmd = find_pairing(conn);
7930
7931 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7932 cmd ? cmd->sk : NULL);
7933
Johan Hedberga511b352014-12-11 21:45:45 +02007934 if (cmd) {
7935 cmd->cmd_complete(cmd, status);
7936 mgmt_pending_remove(cmd);
7937 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007938}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007939
Marcel Holtmann464996a2013-10-15 14:26:24 -07007940void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007941{
7942 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007943 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007944
7945 if (status) {
7946 u8 mgmt_err = mgmt_status(status);
7947 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007948 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007949 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007950 }
7951
Marcel Holtmann464996a2013-10-15 14:26:24 -07007952 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007953 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007954 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007955 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007956
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007957 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007958 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007959
Johan Hedberg47990ea2012-02-22 11:58:37 +02007960 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007961 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007962
7963 if (match.sk)
7964 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007965}
7966
Johan Hedberg890ea892013-03-15 17:06:52 -05007967static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007968{
Johan Hedberg890ea892013-03-15 17:06:52 -05007969 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007970 struct hci_cp_write_eir cp;
7971
Johan Hedberg976eb202012-10-24 21:12:01 +03007972 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007973 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007974
Johan Hedbergc80da272012-02-22 15:38:48 +02007975 memset(hdev->eir, 0, sizeof(hdev->eir));
7976
Johan Hedbergcacaf522012-02-21 00:52:42 +02007977 memset(&cp, 0, sizeof(cp));
7978
Johan Hedberg890ea892013-03-15 17:06:52 -05007979 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007980}
7981
Marcel Holtmann3e248562013-10-15 14:26:25 -07007982void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007983{
7984 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007985 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007986 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007987
7988 if (status) {
7989 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007990
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007991 if (enable && hci_dev_test_and_clear_flag(hdev,
7992 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007993 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007994 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007995 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007996
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007997 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7998 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007999 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008000 }
8001
8002 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008003 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008004 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008005 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008006 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008007 changed = hci_dev_test_and_clear_flag(hdev,
8008 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008009 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008010 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008011 }
8012
8013 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8014
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008015 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008016 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008017
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008018 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008019 sock_put(match.sk);
8020
Johan Hedberg890ea892013-03-15 17:06:52 -05008021 hci_req_init(&req, hdev);
8022
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008023 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8024 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008025 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8026 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02008027 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008028 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008029 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008030 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008031
8032 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008033}
8034
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008035static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008036{
8037 struct cmd_lookup *match = data;
8038
Johan Hedberg90e70452012-02-23 23:09:40 +02008039 if (match->sk == NULL) {
8040 match->sk = cmd->sk;
8041 sock_hold(match->sk);
8042 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008043}
8044
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008045void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8046 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008047{
Johan Hedberg90e70452012-02-23 23:09:40 +02008048 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008049
Johan Hedberg92da6092013-03-15 17:06:55 -05008050 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8051 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8052 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008053
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008054 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008055 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
8056 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008057 ext_info_changed(hdev, NULL);
8058 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008059
8060 if (match.sk)
8061 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008062}
8063
Marcel Holtmann7667da32013-10-15 14:26:27 -07008064void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008065{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008066 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008067 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008068
Johan Hedberg13928972013-03-15 17:07:00 -05008069 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008070 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008071
8072 memset(&ev, 0, sizeof(ev));
8073 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008074 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008075
Johan Hedberg333ae952015-03-17 13:48:47 +02008076 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008077 if (!cmd) {
8078 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008079
Johan Hedberg13928972013-03-15 17:07:00 -05008080 /* If this is a HCI command related to powering on the
8081 * HCI dev don't send any mgmt signals.
8082 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008083 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008084 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008085 }
8086
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02008087 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8088 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02008089 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008090}
Szymon Jancc35938b2011-03-22 13:12:21 +01008091
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008092static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8093{
8094 int i;
8095
8096 for (i = 0; i < uuid_count; i++) {
8097 if (!memcmp(uuid, uuids[i], 16))
8098 return true;
8099 }
8100
8101 return false;
8102}
8103
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008104static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8105{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008106 u16 parsed = 0;
8107
8108 while (parsed < eir_len) {
8109 u8 field_len = eir[0];
8110 u8 uuid[16];
8111 int i;
8112
8113 if (field_len == 0)
8114 break;
8115
8116 if (eir_len - parsed < field_len + 1)
8117 break;
8118
8119 switch (eir[1]) {
8120 case EIR_UUID16_ALL:
8121 case EIR_UUID16_SOME:
8122 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008123 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008124 uuid[13] = eir[i + 3];
8125 uuid[12] = eir[i + 2];
8126 if (has_uuid(uuid, uuid_count, uuids))
8127 return true;
8128 }
8129 break;
8130 case EIR_UUID32_ALL:
8131 case EIR_UUID32_SOME:
8132 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008133 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008134 uuid[15] = eir[i + 5];
8135 uuid[14] = eir[i + 4];
8136 uuid[13] = eir[i + 3];
8137 uuid[12] = eir[i + 2];
8138 if (has_uuid(uuid, uuid_count, uuids))
8139 return true;
8140 }
8141 break;
8142 case EIR_UUID128_ALL:
8143 case EIR_UUID128_SOME:
8144 for (i = 0; i + 17 <= field_len; i += 16) {
8145 memcpy(uuid, eir + i + 2, 16);
8146 if (has_uuid(uuid, uuid_count, uuids))
8147 return true;
8148 }
8149 break;
8150 }
8151
8152 parsed += field_len + 1;
8153 eir += field_len + 1;
8154 }
8155
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008156 return false;
8157}
8158
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008159static void restart_le_scan(struct hci_dev *hdev)
8160{
8161 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008162 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008163 return;
8164
8165 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8166 hdev->discovery.scan_start +
8167 hdev->discovery.scan_duration))
8168 return;
8169
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02008170 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008171 DISCOV_LE_RESTART_DELAY);
8172}
8173
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008174static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8175 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8176{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008177 /* If a RSSI threshold has been specified, and
8178 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8179 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8180 * is set, let it through for further processing, as we might need to
8181 * restart the scan.
8182 *
8183 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8184 * the results are also dropped.
8185 */
8186 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8187 (rssi == HCI_RSSI_INVALID ||
8188 (rssi < hdev->discovery.rssi &&
8189 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8190 return false;
8191
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008192 if (hdev->discovery.uuid_count != 0) {
8193 /* If a list of UUIDs is provided in filter, results with no
8194 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008195 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008196 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8197 hdev->discovery.uuids) &&
8198 !eir_has_uuids(scan_rsp, scan_rsp_len,
8199 hdev->discovery.uuid_count,
8200 hdev->discovery.uuids))
8201 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008202 }
8203
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008204 /* If duplicate filtering does not report RSSI changes, then restart
8205 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008206 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008207 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8208 restart_le_scan(hdev);
8209
8210 /* Validate RSSI value against the RSSI threshold once more. */
8211 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8212 rssi < hdev->discovery.rssi)
8213 return false;
8214 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008215
8216 return true;
8217}
8218
Marcel Holtmann901801b2013-10-06 23:55:51 -07008219void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008220 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8221 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008222{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008223 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008224 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008225 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008226
Johan Hedberg75ce2082014-07-02 22:42:01 +03008227 /* Don't send events for a non-kernel initiated discovery. With
8228 * LE one exception is if we have pend_le_reports > 0 in which
8229 * case we're doing passive scanning and want these events.
8230 */
8231 if (!hci_discovery_active(hdev)) {
8232 if (link_type == ACL_LINK)
8233 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03008234 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03008235 return;
8236 }
Andre Guedes12602d02013-04-30 15:29:40 -03008237
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008238 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008239 /* We are using service discovery */
8240 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8241 scan_rsp_len))
8242 return;
8243 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008244
Johan Hedberg78b781c2016-01-05 13:19:32 +02008245 if (hdev->discovery.limited) {
8246 /* Check for limited discoverable bit */
8247 if (dev_class) {
8248 if (!(dev_class[1] & 0x20))
8249 return;
8250 } else {
8251 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8252 if (!flags || !(flags[0] & LE_AD_LIMITED))
8253 return;
8254 }
8255 }
8256
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008257 /* Make sure that the buffer is big enough. The 5 extra bytes
8258 * are for the potential CoD field.
8259 */
8260 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008261 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008262
Johan Hedberg1dc06092012-01-15 21:01:23 +02008263 memset(buf, 0, sizeof(buf));
8264
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008265 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8266 * RSSI value was reported as 0 when not available. This behavior
8267 * is kept when using device discovery. This is required for full
8268 * backwards compatibility with the API.
8269 *
8270 * However when using service discovery, the value 127 will be
8271 * returned when the RSSI is not available.
8272 */
Szymon Janc91200e92015-01-22 16:57:05 +01008273 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8274 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008275 rssi = 0;
8276
Johan Hedberg841c5642014-07-07 12:45:54 +03008277 bacpy(&ev->addr.bdaddr, bdaddr);
8278 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008279 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008280 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008281
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008282 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008283 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008284 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008285
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008286 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8287 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008288 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008289 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008290
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008291 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008292 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008293 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008294
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008295 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8296 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008297
Marcel Holtmann901801b2013-10-06 23:55:51 -07008298 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008299}
Johan Hedberga88a9652011-03-30 13:18:12 +03008300
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008301void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8302 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008303{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008304 struct mgmt_ev_device_found *ev;
8305 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8306 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008307
Johan Hedbergb644ba32012-01-17 21:48:47 +02008308 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008309
Johan Hedbergb644ba32012-01-17 21:48:47 +02008310 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008311
Johan Hedbergb644ba32012-01-17 21:48:47 +02008312 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008313 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008314 ev->rssi = rssi;
8315
8316 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008317 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008318
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008319 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008320
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008321 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008322}
Johan Hedberg314b2382011-04-27 10:29:57 -04008323
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008324void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008325{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008326 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008327
Marcel Holtmann181d6952020-05-06 09:57:47 +02008328 bt_dev_dbg(hdev, "discovering %u", discovering);
Andre Guedes343fb142011-11-22 17:14:19 -03008329
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008330 memset(&ev, 0, sizeof(ev));
8331 ev.type = hdev->discovery.type;
8332 ev.discovering = discovering;
8333
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008334 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008335}
Antti Julku5e762442011-08-25 16:48:02 +03008336
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008337static struct hci_mgmt_chan chan = {
8338 .channel = HCI_CHANNEL_CONTROL,
8339 .handler_count = ARRAY_SIZE(mgmt_handlers),
8340 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008341 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008342};
8343
8344int mgmt_init(void)
8345{
8346 return hci_mgmt_chan_register(&chan);
8347}
8348
8349void mgmt_exit(void)
8350{
8351 hci_mgmt_chan_unregister(&chan);
8352}