blob: 6552003a170eb4c0c5f51e069279f4f9823c5734 [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"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Marcel Holtmann985048f2020-03-08 09:12:50 +010041#define MGMT_REVISION 16
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200107 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200108 MGMT_OP_SET_APPEARANCE,
Alain Michaud600a8742020-01-07 00:43:17 +0000109 MGMT_OP_SET_BLOCKED_KEYS,
Alain Michaud00bce3f2020-03-05 16:14:59 +0000110 MGMT_OP_SET_WIDEBAND_SPEECH,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200111};
112
113static const u16 mgmt_events[] = {
114 MGMT_EV_CONTROLLER_ERROR,
115 MGMT_EV_INDEX_ADDED,
116 MGMT_EV_INDEX_REMOVED,
117 MGMT_EV_NEW_SETTINGS,
118 MGMT_EV_CLASS_OF_DEV_CHANGED,
119 MGMT_EV_LOCAL_NAME_CHANGED,
120 MGMT_EV_NEW_LINK_KEY,
121 MGMT_EV_NEW_LONG_TERM_KEY,
122 MGMT_EV_DEVICE_CONNECTED,
123 MGMT_EV_DEVICE_DISCONNECTED,
124 MGMT_EV_CONNECT_FAILED,
125 MGMT_EV_PIN_CODE_REQUEST,
126 MGMT_EV_USER_CONFIRM_REQUEST,
127 MGMT_EV_USER_PASSKEY_REQUEST,
128 MGMT_EV_AUTH_FAILED,
129 MGMT_EV_DEVICE_FOUND,
130 MGMT_EV_DISCOVERING,
131 MGMT_EV_DEVICE_BLOCKED,
132 MGMT_EV_DEVICE_UNBLOCKED,
133 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300134 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800135 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700136 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200137 MGMT_EV_DEVICE_ADDED,
138 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300139 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200140 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200141 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200142 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700143 MGMT_EV_EXT_INDEX_ADDED,
144 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700145 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700146 MGMT_EV_ADVERTISING_ADDED,
147 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200148 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200149};
150
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700151static const u16 mgmt_untrusted_commands[] = {
152 MGMT_OP_READ_INDEX_LIST,
153 MGMT_OP_READ_INFO,
154 MGMT_OP_READ_UNCONF_INDEX_LIST,
155 MGMT_OP_READ_CONFIG_INFO,
156 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200157 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700158};
159
160static const u16 mgmt_untrusted_events[] = {
161 MGMT_EV_INDEX_ADDED,
162 MGMT_EV_INDEX_REMOVED,
163 MGMT_EV_NEW_SETTINGS,
164 MGMT_EV_CLASS_OF_DEV_CHANGED,
165 MGMT_EV_LOCAL_NAME_CHANGED,
166 MGMT_EV_UNCONF_INDEX_ADDED,
167 MGMT_EV_UNCONF_INDEX_REMOVED,
168 MGMT_EV_NEW_CONFIG_OPTIONS,
169 MGMT_EV_EXT_INDEX_ADDED,
170 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200171 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700172};
173
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800174#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200175
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200176#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
177 "\x00\x00\x00\x00\x00\x00\x00\x00"
178
Johan Hedbergca69b792011-11-11 18:10:00 +0200179/* HCI to MGMT error code conversion table */
Alain Michaudbdf2aca2020-01-22 16:09:16 +0000180static const u8 mgmt_status_table[] = {
Johan Hedbergca69b792011-11-11 18:10:00 +0200181 MGMT_STATUS_SUCCESS,
182 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
183 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
184 MGMT_STATUS_FAILED, /* Hardware Failure */
185 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
186 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200187 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200188 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
189 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
190 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
191 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
192 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
193 MGMT_STATUS_BUSY, /* Command Disallowed */
194 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
195 MGMT_STATUS_REJECTED, /* Rejected Security */
196 MGMT_STATUS_REJECTED, /* Rejected Personal */
197 MGMT_STATUS_TIMEOUT, /* Host Timeout */
198 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
199 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
200 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
201 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
202 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
203 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
204 MGMT_STATUS_BUSY, /* Repeated Attempts */
205 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
206 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
207 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
208 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
209 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
210 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
211 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
212 MGMT_STATUS_FAILED, /* Unspecified Error */
213 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
214 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
215 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
216 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
217 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
218 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
219 MGMT_STATUS_FAILED, /* Unit Link Key Used */
220 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
221 MGMT_STATUS_TIMEOUT, /* Instant Passed */
222 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
223 MGMT_STATUS_FAILED, /* Transaction Collision */
224 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
225 MGMT_STATUS_REJECTED, /* QoS Rejected */
226 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
227 MGMT_STATUS_REJECTED, /* Insufficient Security */
228 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
229 MGMT_STATUS_BUSY, /* Role Switch Pending */
230 MGMT_STATUS_FAILED, /* Slot Violation */
231 MGMT_STATUS_FAILED, /* Role Switch Failed */
232 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
233 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
234 MGMT_STATUS_BUSY, /* Host Busy Pairing */
235 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
236 MGMT_STATUS_BUSY, /* Controller Busy */
237 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
238 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
239 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
240 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
241 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
242};
243
244static u8 mgmt_status(u8 hci_status)
245{
246 if (hci_status < ARRAY_SIZE(mgmt_status_table))
247 return mgmt_status_table[hci_status];
248
249 return MGMT_STATUS_FAILED;
250}
251
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700252static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
253 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700254{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700255 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
256 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700257}
258
Marcel Holtmann72000df2015-03-16 16:11:21 -0700259static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
260 u16 len, int flag, struct sock *skip_sk)
261{
262 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
263 flag, skip_sk);
264}
265
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200266static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
267 struct sock *skip_sk)
268{
269 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700270 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200271}
272
Johan Hedberg85813a72015-10-21 18:02:59 +0300273static u8 le_addr_type(u8 mgmt_addr_type)
274{
275 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
276 return ADDR_LE_DEV_PUBLIC;
277 else
278 return ADDR_LE_DEV_RANDOM;
279}
280
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200281void mgmt_fill_version_info(void *ver)
282{
283 struct mgmt_rp_read_version *rp = ver;
284
285 rp->version = MGMT_VERSION;
286 rp->revision = cpu_to_le16(MGMT_REVISION);
287}
288
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300289static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
290 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200291{
292 struct mgmt_rp_read_version rp;
293
294 BT_DBG("sock %p", sk);
295
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200296 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200297
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200298 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
299 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200300}
301
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300302static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
303 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304{
305 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700306 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307 size_t rp_size;
308 int i, err;
309
310 BT_DBG("sock %p", sk);
311
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700312 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
313 num_commands = ARRAY_SIZE(mgmt_commands);
314 num_events = ARRAY_SIZE(mgmt_events);
315 } else {
316 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
317 num_events = ARRAY_SIZE(mgmt_untrusted_events);
318 }
319
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
321
322 rp = kmalloc(rp_size, GFP_KERNEL);
323 if (!rp)
324 return -ENOMEM;
325
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700326 rp->num_commands = cpu_to_le16(num_commands);
327 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700329 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
330 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200331
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_events[i], opcode);
337 } else {
338 __le16 *opcode = rp->opcodes;
339
340 for (i = 0; i < num_commands; i++, opcode++)
341 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
342
343 for (i = 0; i < num_events; i++, opcode++)
344 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
345 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200347 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
348 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200349 kfree(rp);
350
351 return err;
352}
353
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300354static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
355 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200358 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200359 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300361 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200362
363 BT_DBG("sock %p", sk);
364
365 read_lock(&hci_dev_list_lock);
366
367 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300368 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200369 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700370 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700371 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372 }
373
Johan Hedberga38528f2011-01-22 06:46:43 +0200374 rp_len = sizeof(*rp) + (2 * count);
375 rp = kmalloc(rp_len, GFP_ATOMIC);
376 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100377 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100379 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380
Johan Hedberg476e44c2012-10-19 20:10:46 +0300381 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200382 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700383 if (hci_dev_test_flag(d, HCI_SETUP) ||
384 hci_dev_test_flag(d, HCI_CONFIG) ||
385 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200386 continue;
387
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200388 /* Devices marked as raw-only are neither configured
389 * nor unconfigured controllers.
390 */
391 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700392 continue;
393
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200394 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700395 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700396 rp->index[count++] = cpu_to_le16(d->id);
397 BT_DBG("Added hci%u", d->id);
398 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200399 }
400
Johan Hedberg476e44c2012-10-19 20:10:46 +0300401 rp->num_controllers = cpu_to_le16(count);
402 rp_len = sizeof(*rp) + (2 * count);
403
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404 read_unlock(&hci_dev_list_lock);
405
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200406 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
407 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200408
Johan Hedberga38528f2011-01-22 06:46:43 +0200409 kfree(rp);
410
411 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200412}
413
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200414static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
415 void *data, u16 data_len)
416{
417 struct mgmt_rp_read_unconf_index_list *rp;
418 struct hci_dev *d;
419 size_t rp_len;
420 u16 count;
421 int err;
422
423 BT_DBG("sock %p", sk);
424
425 read_lock(&hci_dev_list_lock);
426
427 count = 0;
428 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200429 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700430 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200431 count++;
432 }
433
434 rp_len = sizeof(*rp) + (2 * count);
435 rp = kmalloc(rp_len, GFP_ATOMIC);
436 if (!rp) {
437 read_unlock(&hci_dev_list_lock);
438 return -ENOMEM;
439 }
440
441 count = 0;
442 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700443 if (hci_dev_test_flag(d, HCI_SETUP) ||
444 hci_dev_test_flag(d, HCI_CONFIG) ||
445 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200446 continue;
447
448 /* Devices marked as raw-only are neither configured
449 * nor unconfigured controllers.
450 */
451 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
452 continue;
453
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200454 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700455 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200456 rp->index[count++] = cpu_to_le16(d->id);
457 BT_DBG("Added hci%u", d->id);
458 }
459 }
460
461 rp->num_controllers = cpu_to_le16(count);
462 rp_len = sizeof(*rp) + (2 * count);
463
464 read_unlock(&hci_dev_list_lock);
465
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200466 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
467 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200468
469 kfree(rp);
470
471 return err;
472}
473
Marcel Holtmann96f14742015-03-14 19:27:57 -0700474static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
475 void *data, u16 data_len)
476{
477 struct mgmt_rp_read_ext_index_list *rp;
478 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700479 u16 count;
480 int err;
481
482 BT_DBG("sock %p", sk);
483
484 read_lock(&hci_dev_list_lock);
485
486 count = 0;
487 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200488 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700489 count++;
490 }
491
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600492 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700493 if (!rp) {
494 read_unlock(&hci_dev_list_lock);
495 return -ENOMEM;
496 }
497
498 count = 0;
499 list_for_each_entry(d, &hci_dev_list, list) {
500 if (hci_dev_test_flag(d, HCI_SETUP) ||
501 hci_dev_test_flag(d, HCI_CONFIG) ||
502 hci_dev_test_flag(d, HCI_USER_CHANNEL))
503 continue;
504
505 /* Devices marked as raw-only are neither configured
506 * nor unconfigured controllers.
507 */
508 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
509 continue;
510
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200511 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700512 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
513 rp->entry[count].type = 0x01;
514 else
515 rp->entry[count].type = 0x00;
516 } else if (d->dev_type == HCI_AMP) {
517 rp->entry[count].type = 0x02;
518 } else {
519 continue;
520 }
521
522 rp->entry[count].bus = d->bus;
523 rp->entry[count++].index = cpu_to_le16(d->id);
524 BT_DBG("Added hci%u", d->id);
525 }
526
527 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700528
529 read_unlock(&hci_dev_list_lock);
530
531 /* If this command is called at least once, then all the
532 * default index and unconfigured index events are disabled
533 * and from now on only extended index events are used.
534 */
535 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
536 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
537 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
538
539 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600540 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
541 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700542
543 kfree(rp);
544
545 return err;
546}
547
Marcel Holtmanndbece372014-07-04 18:11:55 +0200548static bool is_configured(struct hci_dev *hdev)
549{
550 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700551 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200552 return false;
553
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800554 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
555 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200556 !bacmp(&hdev->public_addr, BDADDR_ANY))
557 return false;
558
559 return true;
560}
561
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200562static __le32 get_missing_options(struct hci_dev *hdev)
563{
564 u32 options = 0;
565
Marcel Holtmanndbece372014-07-04 18:11:55 +0200566 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700567 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200568 options |= MGMT_OPTION_EXTERNAL_CONFIG;
569
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800570 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
571 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200572 !bacmp(&hdev->public_addr, BDADDR_ANY))
573 options |= MGMT_OPTION_PUBLIC_ADDRESS;
574
575 return cpu_to_le32(options);
576}
577
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200578static int new_options(struct hci_dev *hdev, struct sock *skip)
579{
580 __le32 options = get_missing_options(hdev);
581
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200582 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
583 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200584}
585
Marcel Holtmanndbece372014-07-04 18:11:55 +0200586static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
587{
588 __le32 options = get_missing_options(hdev);
589
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200590 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
591 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200592}
593
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200594static int read_config_info(struct sock *sk, struct hci_dev *hdev,
595 void *data, u16 data_len)
596{
597 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200599
600 BT_DBG("sock %p %s", sk, hdev->name);
601
602 hci_dev_lock(hdev);
603
604 memset(&rp, 0, sizeof(rp));
605 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200606
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200607 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
608 options |= MGMT_OPTION_EXTERNAL_CONFIG;
609
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200610 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200611 options |= MGMT_OPTION_PUBLIC_ADDRESS;
612
613 rp.supported_options = cpu_to_le32(options);
614 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200615
616 hci_dev_unlock(hdev);
617
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200618 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
619 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200620}
621
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530622static u32 get_supported_phys(struct hci_dev *hdev)
623{
624 u32 supported_phys = 0;
625
626 if (lmp_bredr_capable(hdev)) {
627 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
628
629 if (hdev->features[0][0] & LMP_3SLOT)
630 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
631
632 if (hdev->features[0][0] & LMP_5SLOT)
633 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
634
635 if (lmp_edr_2m_capable(hdev)) {
636 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
637
638 if (lmp_edr_3slot_capable(hdev))
639 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
640
641 if (lmp_edr_5slot_capable(hdev))
642 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
643
644 if (lmp_edr_3m_capable(hdev)) {
645 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
646
647 if (lmp_edr_3slot_capable(hdev))
648 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
649
650 if (lmp_edr_5slot_capable(hdev))
651 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
652 }
653 }
654 }
655
656 if (lmp_le_capable(hdev)) {
657 supported_phys |= MGMT_PHY_LE_1M_TX;
658 supported_phys |= MGMT_PHY_LE_1M_RX;
659
660 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
661 supported_phys |= MGMT_PHY_LE_2M_TX;
662 supported_phys |= MGMT_PHY_LE_2M_RX;
663 }
664
665 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
666 supported_phys |= MGMT_PHY_LE_CODED_TX;
667 supported_phys |= MGMT_PHY_LE_CODED_RX;
668 }
669 }
670
671 return supported_phys;
672}
673
674static u32 get_selected_phys(struct hci_dev *hdev)
675{
676 u32 selected_phys = 0;
677
678 if (lmp_bredr_capable(hdev)) {
679 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
680
681 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
682 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
683
684 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
685 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
686
687 if (lmp_edr_2m_capable(hdev)) {
688 if (!(hdev->pkt_type & HCI_2DH1))
689 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
690
691 if (lmp_edr_3slot_capable(hdev) &&
692 !(hdev->pkt_type & HCI_2DH3))
693 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
694
695 if (lmp_edr_5slot_capable(hdev) &&
696 !(hdev->pkt_type & HCI_2DH5))
697 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
698
699 if (lmp_edr_3m_capable(hdev)) {
700 if (!(hdev->pkt_type & HCI_3DH1))
701 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
702
703 if (lmp_edr_3slot_capable(hdev) &&
704 !(hdev->pkt_type & HCI_3DH3))
705 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
706
707 if (lmp_edr_5slot_capable(hdev) &&
708 !(hdev->pkt_type & HCI_3DH5))
709 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
710 }
711 }
712 }
713
714 if (lmp_le_capable(hdev)) {
715 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
716 selected_phys |= MGMT_PHY_LE_1M_TX;
717
718 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
719 selected_phys |= MGMT_PHY_LE_1M_RX;
720
721 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
722 selected_phys |= MGMT_PHY_LE_2M_TX;
723
724 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
725 selected_phys |= MGMT_PHY_LE_2M_RX;
726
727 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
728 selected_phys |= MGMT_PHY_LE_CODED_TX;
729
730 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
731 selected_phys |= MGMT_PHY_LE_CODED_RX;
732 }
733
734 return selected_phys;
735}
736
737static u32 get_configurable_phys(struct hci_dev *hdev)
738{
739 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
740 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
741}
742
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200743static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200744{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200745 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200746
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200747 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300748 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800749 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300750 settings |= MGMT_SETTING_CONNECTABLE;
751 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200752
Andre Guedesed3fa312012-07-24 15:03:46 -0300753 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500754 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
755 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200756 settings |= MGMT_SETTING_BREDR;
757 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700758
759 if (lmp_ssp_capable(hdev)) {
760 settings |= MGMT_SETTING_SSP;
761 settings |= MGMT_SETTING_HS;
762 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800763
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800764 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800765 settings |= MGMT_SETTING_SECURE_CONN;
Alain Michaud4b127bd2020-02-27 18:29:39 +0000766
Alain Michaud00bce3f2020-03-05 16:14:59 +0000767 if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
Alain Michaud4b127bd2020-02-27 18:29:39 +0000768 &hdev->quirks))
Alain Michaud00bce3f2020-03-05 16:14:59 +0000769 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700770 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100771
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300772 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200773 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300774 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300775 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200776 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800777 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300778 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200779
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200780 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
781 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200782 settings |= MGMT_SETTING_CONFIGURATION;
783
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530784 settings |= MGMT_SETTING_PHY_CONFIGURATION;
785
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786 return settings;
787}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200788
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200789static u32 get_current_settings(struct hci_dev *hdev)
790{
791 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200792
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200793 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100794 settings |= MGMT_SETTING_POWERED;
795
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700796 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200797 settings |= MGMT_SETTING_CONNECTABLE;
798
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700799 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500800 settings |= MGMT_SETTING_FAST_CONNECTABLE;
801
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700802 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200803 settings |= MGMT_SETTING_DISCOVERABLE;
804
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700805 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300806 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200807
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700808 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200809 settings |= MGMT_SETTING_BREDR;
810
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700811 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200812 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200813
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700814 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200815 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700817 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200818 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200819
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700820 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200821 settings |= MGMT_SETTING_HS;
822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700823 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300824 settings |= MGMT_SETTING_ADVERTISING;
825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700826 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800827 settings |= MGMT_SETTING_SECURE_CONN;
828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700829 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800830 settings |= MGMT_SETTING_DEBUG_KEYS;
831
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700832 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200833 settings |= MGMT_SETTING_PRIVACY;
834
Marcel Holtmann93690c22015-03-06 10:11:21 -0800835 /* The current setting for static address has two purposes. The
836 * first is to indicate if the static address will be used and
837 * the second is to indicate if it is actually set.
838 *
839 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700840 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800841 * address is actually used decides if the flag is set or not.
842 *
843 * For single mode LE only controllers and dual-mode controllers
844 * with BR/EDR disabled, the existence of the static address will
845 * be evaluated.
846 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700847 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700848 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800849 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
850 if (bacmp(&hdev->static_addr, BDADDR_ANY))
851 settings |= MGMT_SETTING_STATIC_ADDRESS;
852 }
853
Alain Michaud00bce3f2020-03-05 16:14:59 +0000854 if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
855 settings |= MGMT_SETTING_WIDEBAND_SPEECH;
856
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200857 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200858}
859
Johan Hedberg333ae952015-03-17 13:48:47 +0200860static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
861{
862 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
863}
864
Johan Hedberg333ae952015-03-17 13:48:47 +0200865static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
866 struct hci_dev *hdev,
867 const void *data)
868{
869 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
870}
871
Johan Hedbergf2252572015-11-18 12:49:20 +0200872u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300873{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200874 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300875
876 /* If there's a pending mgmt command the flags will not yet have
877 * their final values, so check for this first.
878 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200879 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300880 if (cmd) {
881 struct mgmt_mode *cp = cmd->param;
882 if (cp->val == 0x01)
883 return LE_AD_GENERAL;
884 else if (cp->val == 0x02)
885 return LE_AD_LIMITED;
886 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700887 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300888 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700889 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300890 return LE_AD_GENERAL;
891 }
892
893 return 0;
894}
895
Johan Hedbergf2252572015-11-18 12:49:20 +0200896bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700897{
898 struct mgmt_pending_cmd *cmd;
899
900 /* If there's a pending mgmt command the flag will not yet have
901 * it's final value, so check for this first.
902 */
903 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
904 if (cmd) {
905 struct mgmt_mode *cp = cmd->param;
906
907 return cp->val;
908 }
909
910 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
911}
912
Johan Hedberg7d785252011-12-15 00:47:39 +0200913static void service_cache_off(struct work_struct *work)
914{
915 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300916 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500917 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200918
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700919 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200920 return;
921
Johan Hedberg890ea892013-03-15 17:06:52 -0500922 hci_req_init(&req, hdev);
923
Johan Hedberg7d785252011-12-15 00:47:39 +0200924 hci_dev_lock(hdev);
925
Johan Hedbergb1a89172015-11-25 16:15:42 +0200926 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200927 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200928
929 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500930
931 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200932}
933
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200934static void rpa_expired(struct work_struct *work)
935{
936 struct hci_dev *hdev = container_of(work, struct hci_dev,
937 rpa_expired.work);
938 struct hci_request req;
939
940 BT_DBG("");
941
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700942 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200943
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700944 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200945 return;
946
947 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200948 * controller happens in the hci_req_enable_advertising()
949 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200950 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200951 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530952 if (ext_adv_capable(hdev))
953 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
954 else
955 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200956 hci_req_run(&req, NULL);
957}
958
Johan Hedberg6a919082012-02-28 06:17:26 +0200959static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200960{
Marcel Holtmann238be782015-03-13 02:11:06 -0700961 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200962 return;
963
Johan Hedberg4f87da82012-03-02 19:55:56 +0200964 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200965 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200966
Johan Hedberg4f87da82012-03-02 19:55:56 +0200967 /* Non-mgmt controlled devices get this bit set
968 * implicitly so that pairing works for them, however
969 * for mgmt we require user-space to explicitly enable
970 * it
971 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700972 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200973}
974
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200975static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300976 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200977{
978 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200979
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200980 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200981
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300982 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200983
Johan Hedberg03811012010-12-08 00:21:06 +0200984 memset(&rp, 0, sizeof(rp));
985
Johan Hedberg03811012010-12-08 00:21:06 +0200986 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200987
988 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200989 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200990
991 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
992 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
993
994 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200995
996 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200997 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200998
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300999 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001000
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001001 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1002 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001003}
1004
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001005static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
1006{
1007 u16 eir_len = 0;
1008 size_t name_len;
1009
1010 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1011 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1012 hdev->dev_class, 3);
1013
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001014 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1015 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1016 hdev->appearance);
1017
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001018 name_len = strlen(hdev->dev_name);
1019 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1020 hdev->dev_name, name_len);
1021
1022 name_len = strlen(hdev->short_name);
1023 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1024 hdev->short_name, name_len);
1025
1026 return eir_len;
1027}
1028
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001029static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1030 void *data, u16 data_len)
1031{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001032 char buf[512];
1033 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001034 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001035
1036 BT_DBG("sock %p %s", sk, hdev->name);
1037
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001038 memset(&buf, 0, sizeof(buf));
1039
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001040 hci_dev_lock(hdev);
1041
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001042 bacpy(&rp->bdaddr, &hdev->bdaddr);
1043
1044 rp->version = hdev->hci_ver;
1045 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1046
1047 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1048 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001049
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001050
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001051 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001052 rp->eir_len = cpu_to_le16(eir_len);
1053
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001054 hci_dev_unlock(hdev);
1055
1056 /* If this command is called at least once, then the events
1057 * for class of device and local name changes are disabled
1058 * and only the new extended controller information event
1059 * is used.
1060 */
1061 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1062 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1063 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1064
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001065 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1066 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001067}
1068
1069static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1070{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001071 char buf[512];
1072 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1073 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001074
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001075 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001076
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001077 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1078 ev->eir_len = cpu_to_le16(eir_len);
1079
1080 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1081 sizeof(*ev) + eir_len,
1082 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001083}
1084
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001085static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001086{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001087 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001088
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001089 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1090 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001091}
1092
Marcel Holtmann1904a852015-01-11 13:50:44 -08001093static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001094{
1095 BT_DBG("%s status 0x%02x", hdev->name, status);
1096
Johan Hedberga3172b72014-02-28 09:33:44 +02001097 if (hci_conn_count(hdev) == 0) {
1098 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001099 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001100 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001101}
1102
Johan Hedbergf2252572015-11-18 12:49:20 +02001103void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001104{
1105 struct mgmt_ev_advertising_added ev;
1106
1107 ev.instance = instance;
1108
1109 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1110}
1111
Johan Hedbergf2252572015-11-18 12:49:20 +02001112void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1113 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001114{
1115 struct mgmt_ev_advertising_removed ev;
1116
1117 ev.instance = instance;
1118
1119 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1120}
1121
Florian Grandel7816b822015-06-18 03:16:45 +02001122static void cancel_adv_timeout(struct hci_dev *hdev)
1123{
1124 if (hdev->adv_instance_timeout) {
1125 hdev->adv_instance_timeout = 0;
1126 cancel_delayed_work(&hdev->adv_instance_expire);
1127 }
1128}
1129
Johan Hedberg8b064a32014-02-24 14:52:22 +02001130static int clean_up_hci_state(struct hci_dev *hdev)
1131{
1132 struct hci_request req;
1133 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001134 bool discov_stopped;
1135 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001136
1137 hci_req_init(&req, hdev);
1138
1139 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1140 test_bit(HCI_PSCAN, &hdev->flags)) {
1141 u8 scan = 0x00;
1142 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1143 }
1144
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001145 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001146
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001147 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001148 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001149
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001150 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001151
1152 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001153 /* 0x15 == Terminated due to Power Off */
1154 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001155 }
1156
Johan Hedberg23a48092014-07-08 16:05:06 +03001157 err = hci_req_run(&req, clean_up_hci_complete);
1158 if (!err && discov_stopped)
1159 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1160
1161 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001162}
1163
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001164static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001165 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001167 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001168 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001169 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001171 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001172
Johan Hedberga7e80f22013-01-09 16:05:19 +02001173 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1175 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001176
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001177 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178
Johan Hedberg333ae952015-03-17 13:48:47 +02001179 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001180 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1181 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001182 goto failed;
1183 }
1184
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001185 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001186 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 goto failed;
1188 }
1189
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1191 if (!cmd) {
1192 err = -ENOMEM;
1193 goto failed;
1194 }
1195
Johan Hedberg8b064a32014-02-24 14:52:22 +02001196 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001197 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001198 err = 0;
1199 } else {
1200 /* Disconnect connections, stop scans, etc */
1201 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001202 if (!err)
1203 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1204 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205
Johan Hedberg8b064a32014-02-24 14:52:22 +02001206 /* ENODATA means there were no HCI commands queued */
1207 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001208 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001209 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1210 err = 0;
1211 }
1212 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
1214failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001215 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 return err;
1217}
1218
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001219static int new_settings(struct hci_dev *hdev, struct sock *skip)
1220{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001221 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001222
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001223 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1224 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001225}
1226
Johan Hedberg91a668b2014-07-09 13:28:26 +03001227int mgmt_new_settings(struct hci_dev *hdev)
1228{
1229 return new_settings(hdev, NULL);
1230}
1231
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001232struct cmd_lookup {
1233 struct sock *sk;
1234 struct hci_dev *hdev;
1235 u8 mgmt_status;
1236};
1237
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001238static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001239{
1240 struct cmd_lookup *match = data;
1241
1242 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1243
1244 list_del(&cmd->list);
1245
1246 if (match->sk == NULL) {
1247 match->sk = cmd->sk;
1248 sock_hold(match->sk);
1249 }
1250
1251 mgmt_pending_free(cmd);
1252}
1253
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001254static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001255{
1256 u8 *status = data;
1257
Johan Hedberga69e8372015-03-06 21:08:53 +02001258 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001259 mgmt_pending_remove(cmd);
1260}
1261
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001262static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001263{
1264 if (cmd->cmd_complete) {
1265 u8 *status = data;
1266
1267 cmd->cmd_complete(cmd, *status);
1268 mgmt_pending_remove(cmd);
1269
1270 return;
1271 }
1272
1273 cmd_status_rsp(cmd, data);
1274}
1275
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001276static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001277{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001278 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1279 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001280}
1281
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001282static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001283{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001284 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1285 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001286}
1287
Johan Hedberge6fe7982013-10-02 15:45:22 +03001288static u8 mgmt_bredr_support(struct hci_dev *hdev)
1289{
1290 if (!lmp_bredr_capable(hdev))
1291 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001292 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001293 return MGMT_STATUS_REJECTED;
1294 else
1295 return MGMT_STATUS_SUCCESS;
1296}
1297
1298static u8 mgmt_le_support(struct hci_dev *hdev)
1299{
1300 if (!lmp_le_capable(hdev))
1301 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001302 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001303 return MGMT_STATUS_REJECTED;
1304 else
1305 return MGMT_STATUS_SUCCESS;
1306}
1307
Johan Hedbergaed1a882015-11-22 17:24:44 +03001308void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001309{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001310 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001311
1312 BT_DBG("status 0x%02x", status);
1313
1314 hci_dev_lock(hdev);
1315
Johan Hedberg333ae952015-03-17 13:48:47 +02001316 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001317 if (!cmd)
1318 goto unlock;
1319
1320 if (status) {
1321 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001322 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001323 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001324 goto remove_cmd;
1325 }
1326
Johan Hedbergaed1a882015-11-22 17:24:44 +03001327 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1328 hdev->discov_timeout > 0) {
1329 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1330 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001331 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001332
1333 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001334 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001335
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001336remove_cmd:
1337 mgmt_pending_remove(cmd);
1338
1339unlock:
1340 hci_dev_unlock(hdev);
1341}
1342
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001344 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001345{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001346 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001348 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001349 int err;
1350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001351 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001352
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001353 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1354 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001355 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1356 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001357
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001358 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001359 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001361
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001362 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001363
1364 /* Disabling discoverable requires that no timeout is set,
1365 * and enabling limited discoverable requires a timeout.
1366 */
1367 if ((cp->val == 0x00 && timeout > 0) ||
1368 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001369 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001373
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001374 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001375 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1376 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001377 goto failed;
1378 }
1379
Johan Hedberg333ae952015-03-17 13:48:47 +02001380 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1381 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001382 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1383 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001384 goto failed;
1385 }
1386
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001387 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001388 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1389 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001390 goto failed;
1391 }
1392
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07001393 if (hdev->advertising_paused) {
1394 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1395 MGMT_STATUS_BUSY);
1396 goto failed;
1397 }
1398
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001399 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001400 bool changed = false;
1401
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001402 /* Setting limited discoverable when powered off is
1403 * not a valid operation since it requires a timeout
1404 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1405 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001406 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001407 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001408 changed = true;
1409 }
1410
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001411 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001412 if (err < 0)
1413 goto failed;
1414
1415 if (changed)
1416 err = new_settings(hdev, sk);
1417
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001418 goto failed;
1419 }
1420
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001421 /* If the current mode is the same, then just update the timeout
1422 * value with the new value. And if only the timeout gets updated,
1423 * then no need for any HCI transactions.
1424 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001425 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1426 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1427 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001428 cancel_delayed_work(&hdev->discov_off);
1429 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001430
Marcel Holtmann36261542013-10-15 08:28:51 -07001431 if (cp->val && hdev->discov_timeout > 0) {
1432 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001433 queue_delayed_work(hdev->req_workqueue,
1434 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001435 }
1436
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001437 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001438 goto failed;
1439 }
1440
1441 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1442 if (!cmd) {
1443 err = -ENOMEM;
1444 goto failed;
1445 }
1446
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001447 /* Cancel any potential discoverable timeout that might be
1448 * still active and store new timeout value. The arming of
1449 * the timeout happens in the complete handler.
1450 */
1451 cancel_delayed_work(&hdev->discov_off);
1452 hdev->discov_timeout = timeout;
1453
Johan Hedbergaed1a882015-11-22 17:24:44 +03001454 if (cp->val)
1455 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1456 else
1457 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1458
Johan Hedbergb456f872013-10-19 23:38:22 +03001459 /* Limited discoverable mode */
1460 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001461 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001462 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001463 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001464
Johan Hedbergaed1a882015-11-22 17:24:44 +03001465 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1466 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001467
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001468failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001469 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001470 return err;
1471}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001472
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001473void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001474{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001475 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001476
1477 BT_DBG("status 0x%02x", status);
1478
1479 hci_dev_lock(hdev);
1480
Johan Hedberg333ae952015-03-17 13:48:47 +02001481 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001482 if (!cmd)
1483 goto unlock;
1484
Johan Hedberg37438c12013-10-14 16:20:05 +03001485 if (status) {
1486 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001487 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001488 goto remove_cmd;
1489 }
1490
Johan Hedberg2b76f452013-03-15 17:07:04 -05001491 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001492 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001493
Johan Hedberg37438c12013-10-14 16:20:05 +03001494remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001495 mgmt_pending_remove(cmd);
1496
1497unlock:
1498 hci_dev_unlock(hdev);
1499}
1500
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001501static int set_connectable_update_settings(struct hci_dev *hdev,
1502 struct sock *sk, u8 val)
1503{
1504 bool changed = false;
1505 int err;
1506
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001507 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001508 changed = true;
1509
1510 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001511 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001512 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001513 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1514 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001515 }
1516
1517 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1518 if (err < 0)
1519 return err;
1520
Johan Hedberg562064e2014-07-08 16:35:34 +03001521 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001522 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001523 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001524 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001525 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001526
1527 return 0;
1528}
1529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001530static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001531 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001532{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001533 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001534 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001535 int err;
1536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001537 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001538
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001539 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1540 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001541 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1542 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001543
Johan Hedberga7e80f22013-01-09 16:05:19 +02001544 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001545 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1546 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001547
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001548 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001549
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001550 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001551 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001552 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553 }
1554
Johan Hedberg333ae952015-03-17 13:48:47 +02001555 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1556 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1558 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001559 goto failed;
1560 }
1561
Johan Hedberg73f22f62010-12-29 16:00:25 +02001562 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1563 if (!cmd) {
1564 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001565 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001566 }
1567
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001568 if (cp->val) {
1569 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1570 } else {
1571 if (hdev->discov_timeout > 0)
1572 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001573
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001574 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1575 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1576 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001577 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001578
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001579 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1580 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001581
1582failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001584 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001585}
1586
Johan Hedbergb2939472014-07-30 09:22:23 +03001587static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001588 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001590 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001591 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001592 int err;
1593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001595
Johan Hedberga7e80f22013-01-09 16:05:19 +02001596 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001597 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1598 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001599
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001600 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001601
1602 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001603 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001604 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001605 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001606
Johan Hedbergb2939472014-07-30 09:22:23 +03001607 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001608 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001609 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001610
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001611 if (changed) {
1612 /* In limited privacy mode the change of bondable mode
1613 * may affect the local advertising address.
1614 */
1615 if (hdev_is_powered(hdev) &&
1616 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1617 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1618 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1619 queue_work(hdev->req_workqueue,
1620 &hdev->discoverable_update);
1621
Marcel Holtmann55594352013-10-06 16:11:57 -07001622 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001623 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001624
Marcel Holtmann55594352013-10-06 16:11:57 -07001625unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001626 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001627 return err;
1628}
1629
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001630static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1631 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001632{
1633 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001634 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001635 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001636 int err;
1637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001639
Johan Hedberge6fe7982013-10-02 15:45:22 +03001640 status = mgmt_bredr_support(hdev);
1641 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001642 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1643 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001644
Johan Hedberga7e80f22013-01-09 16:05:19 +02001645 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001646 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1647 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001648
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001649 hci_dev_lock(hdev);
1650
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001651 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001652 bool changed = false;
1653
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001654 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001655 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001656 changed = true;
1657 }
1658
1659 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1660 if (err < 0)
1661 goto failed;
1662
1663 if (changed)
1664 err = new_settings(hdev, sk);
1665
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001666 goto failed;
1667 }
1668
Johan Hedberg333ae952015-03-17 13:48:47 +02001669 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001670 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1671 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001672 goto failed;
1673 }
1674
1675 val = !!cp->val;
1676
1677 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1678 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1679 goto failed;
1680 }
1681
1682 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1683 if (!cmd) {
1684 err = -ENOMEM;
1685 goto failed;
1686 }
1687
1688 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1689 if (err < 0) {
1690 mgmt_pending_remove(cmd);
1691 goto failed;
1692 }
1693
1694failed:
1695 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001696 return err;
1697}
1698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001699static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001700{
1701 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001702 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001703 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001704 int err;
1705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001706 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001707
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001708 status = mgmt_bredr_support(hdev);
1709 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001710 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001711
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001712 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1714 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001715
Johan Hedberga7e80f22013-01-09 16:05:19 +02001716 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1718 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001719
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001720 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001721
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001722 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001723 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001724
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001725 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001726 changed = !hci_dev_test_and_set_flag(hdev,
1727 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001728 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001729 changed = hci_dev_test_and_clear_flag(hdev,
1730 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001731 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001732 changed = hci_dev_test_and_clear_flag(hdev,
1733 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001734 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001735 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001736 }
1737
1738 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1739 if (err < 0)
1740 goto failed;
1741
1742 if (changed)
1743 err = new_settings(hdev, sk);
1744
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001745 goto failed;
1746 }
1747
Johan Hedberg333ae952015-03-17 13:48:47 +02001748 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001749 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1750 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001751 goto failed;
1752 }
1753
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001754 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001755 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1756 goto failed;
1757 }
1758
1759 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1760 if (!cmd) {
1761 err = -ENOMEM;
1762 goto failed;
1763 }
1764
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001765 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001766 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1767 sizeof(cp->val), &cp->val);
1768
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001769 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001770 if (err < 0) {
1771 mgmt_pending_remove(cmd);
1772 goto failed;
1773 }
1774
1775failed:
1776 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001777 return err;
1778}
1779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001780static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001781{
1782 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001783 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001784 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001785 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001786
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001788
Johan Hedberge6fe7982013-10-02 15:45:22 +03001789 status = mgmt_bredr_support(hdev);
1790 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001791 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001792
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001793 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1795 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001796
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001797 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1799 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001800
Johan Hedberga7e80f22013-01-09 16:05:19 +02001801 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001802 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1803 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001804
Marcel Holtmannee392692013-10-01 22:59:23 -07001805 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001806
Johan Hedberg333ae952015-03-17 13:48:47 +02001807 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001808 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1809 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001810 goto unlock;
1811 }
1812
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001813 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001814 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001815 } else {
1816 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001817 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1818 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001819 goto unlock;
1820 }
1821
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001822 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001823 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001824
1825 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1826 if (err < 0)
1827 goto unlock;
1828
1829 if (changed)
1830 err = new_settings(hdev, sk);
1831
1832unlock:
1833 hci_dev_unlock(hdev);
1834 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001835}
1836
Marcel Holtmann1904a852015-01-11 13:50:44 -08001837static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001838{
1839 struct cmd_lookup match = { NULL, hdev };
1840
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301841 hci_dev_lock(hdev);
1842
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001843 if (status) {
1844 u8 mgmt_err = mgmt_status(status);
1845
1846 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1847 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301848 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001849 }
1850
1851 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1852
1853 new_settings(hdev, match.sk);
1854
1855 if (match.sk)
1856 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001857
1858 /* Make sure the controller has a good default for
1859 * advertising data. Restrict the update to when LE
1860 * has actually been enabled. During power on, the
1861 * update in powered_update_hci will take care of it.
1862 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001863 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001864 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001865 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301866 if (ext_adv_capable(hdev)) {
1867 int err;
1868
1869 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1870 if (!err)
1871 __hci_req_update_scan_rsp_data(&req, 0x00);
1872 } else {
1873 __hci_req_update_adv_data(&req, 0x00);
1874 __hci_req_update_scan_rsp_data(&req, 0x00);
1875 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001876 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001877 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001878 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301879
1880unlock:
1881 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001882}
1883
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001884static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001885{
1886 struct mgmt_mode *cp = data;
1887 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001888 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001889 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001890 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001891 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001892
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001893 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001894
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001895 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001896 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1897 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001898
Johan Hedberga7e80f22013-01-09 16:05:19 +02001899 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001900 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1901 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001902
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001903 /* Bluetooth single mode LE only controllers or dual-mode
1904 * controllers configured as LE only devices, do not allow
1905 * switching LE off. These have either LE enabled explicitly
1906 * or BR/EDR has been previously switched off.
1907 *
1908 * When trying to enable an already enabled LE, then gracefully
1909 * send a positive response. Trying to disable it however will
1910 * result into rejection.
1911 */
1912 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1913 if (cp->val == 0x01)
1914 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1915
Johan Hedberga69e8372015-03-06 21:08:53 +02001916 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1917 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001918 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001919
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001920 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001921
1922 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001923 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001924
Florian Grandel847818d2015-06-18 03:16:46 +02001925 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001926 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001927
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001928 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929 bool changed = false;
1930
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001931 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001932 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001933 changed = true;
1934 }
1935
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001936 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001937 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001938 changed = true;
1939 }
1940
Johan Hedberg06199cf2012-02-22 16:37:11 +02001941 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1942 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001943 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944
1945 if (changed)
1946 err = new_settings(hdev, sk);
1947
Johan Hedberg1de028c2012-02-29 19:55:35 -08001948 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001949 }
1950
Johan Hedberg333ae952015-03-17 13:48:47 +02001951 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1952 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001953 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1954 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001955 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001956 }
1957
1958 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1959 if (!cmd) {
1960 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001961 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001964 hci_req_init(&req, hdev);
1965
Johan Hedberg06199cf2012-02-22 16:37:11 +02001966 memset(&hci_cp, 0, sizeof(hci_cp));
1967
1968 if (val) {
1969 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001970 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001971 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001972 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001973 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301974
1975 if (ext_adv_capable(hdev))
1976 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001977 }
1978
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001979 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1980 &hci_cp);
1981
1982 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301983 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001984 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001985
Johan Hedberg1de028c2012-02-29 19:55:35 -08001986unlock:
1987 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001988 return err;
1989}
1990
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001991/* This is a helper function to test for pending mgmt commands that can
1992 * cause CoD or EIR HCI commands. We can only allow one such pending
1993 * mgmt command at a time since otherwise we cannot easily track what
1994 * the current values are, will be, and based on that calculate if a new
1995 * HCI command needs to be sent and if yes with what value.
1996 */
1997static bool pending_eir_or_class(struct hci_dev *hdev)
1998{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001999 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002000
2001 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2002 switch (cmd->opcode) {
2003 case MGMT_OP_ADD_UUID:
2004 case MGMT_OP_REMOVE_UUID:
2005 case MGMT_OP_SET_DEV_CLASS:
2006 case MGMT_OP_SET_POWERED:
2007 return true;
2008 }
2009 }
2010
2011 return false;
2012}
2013
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002014static const u8 bluetooth_base_uuid[] = {
2015 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2016 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2017};
2018
2019static u8 get_uuid_size(const u8 *uuid)
2020{
2021 u32 val;
2022
2023 if (memcmp(uuid, bluetooth_base_uuid, 12))
2024 return 128;
2025
2026 val = get_unaligned_le32(&uuid[12]);
2027 if (val > 0xffff)
2028 return 32;
2029
2030 return 16;
2031}
2032
Johan Hedberg92da6092013-03-15 17:06:55 -05002033static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2034{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002035 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002036
2037 hci_dev_lock(hdev);
2038
Johan Hedberg333ae952015-03-17 13:48:47 +02002039 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002040 if (!cmd)
2041 goto unlock;
2042
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002043 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2044 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002045
2046 mgmt_pending_remove(cmd);
2047
2048unlock:
2049 hci_dev_unlock(hdev);
2050}
2051
Marcel Holtmann1904a852015-01-11 13:50:44 -08002052static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002053{
2054 BT_DBG("status 0x%02x", status);
2055
2056 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2057}
2058
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002059static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002060{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002061 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002062 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002063 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002064 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065 int err;
2066
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002067 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002070
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002071 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002072 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2073 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002074 goto failed;
2075 }
2076
Andre Guedes92c4c202012-06-07 19:05:44 -03002077 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002078 if (!uuid) {
2079 err = -ENOMEM;
2080 goto failed;
2081 }
2082
2083 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002085 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002086
Johan Hedbergde66aa62013-01-27 00:31:27 +02002087 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088
Johan Hedberg890ea892013-03-15 17:06:52 -05002089 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002091 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002092 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002093
Johan Hedberg92da6092013-03-15 17:06:55 -05002094 err = hci_req_run(&req, add_uuid_complete);
2095 if (err < 0) {
2096 if (err != -ENODATA)
2097 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002098
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002099 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2100 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002101 goto failed;
2102 }
2103
2104 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002105 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002106 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002107 goto failed;
2108 }
2109
2110 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002111
2112failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002113 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002114 return err;
2115}
2116
Johan Hedberg24b78d02012-02-23 23:24:30 +02002117static bool enable_service_cache(struct hci_dev *hdev)
2118{
2119 if (!hdev_is_powered(hdev))
2120 return false;
2121
Marcel Holtmann238be782015-03-13 02:11:06 -07002122 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002123 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2124 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002125 return true;
2126 }
2127
2128 return false;
2129}
2130
Marcel Holtmann1904a852015-01-11 13:50:44 -08002131static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002132{
2133 BT_DBG("status 0x%02x", status);
2134
2135 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2136}
2137
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002138static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002139 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002140{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002141 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002142 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002143 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002144 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 -05002145 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002146 int err, found;
2147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002148 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002151
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002152 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002153 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2154 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002155 goto unlock;
2156 }
2157
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002158 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002159 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002160
Johan Hedberg24b78d02012-02-23 23:24:30 +02002161 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002162 err = mgmt_cmd_complete(sk, hdev->id,
2163 MGMT_OP_REMOVE_UUID,
2164 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002165 goto unlock;
2166 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002167
Johan Hedberg9246a862012-02-23 21:33:16 +02002168 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002169 }
2170
2171 found = 0;
2172
Johan Hedberg056341c2013-01-27 00:31:30 +02002173 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002174 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2175 continue;
2176
2177 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002178 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002179 found++;
2180 }
2181
2182 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002183 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2184 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002185 goto unlock;
2186 }
2187
Johan Hedberg9246a862012-02-23 21:33:16 +02002188update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002189 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002190
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002191 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002192 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002193
Johan Hedberg92da6092013-03-15 17:06:55 -05002194 err = hci_req_run(&req, remove_uuid_complete);
2195 if (err < 0) {
2196 if (err != -ENODATA)
2197 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002198
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002199 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2200 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002201 goto unlock;
2202 }
2203
2204 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002205 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002206 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002207 goto unlock;
2208 }
2209
2210 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002211
2212unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002213 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002214 return err;
2215}
2216
Marcel Holtmann1904a852015-01-11 13:50:44 -08002217static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002218{
2219 BT_DBG("status 0x%02x", status);
2220
2221 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2222}
2223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002224static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002225 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002226{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002227 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002228 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002229 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002230 int err;
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002233
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002234 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002235 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2236 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002237
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002238 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002239
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002240 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002241 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2242 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002243 goto unlock;
2244 }
2245
2246 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002247 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2248 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002249 goto unlock;
2250 }
2251
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002252 hdev->major_class = cp->major;
2253 hdev->minor_class = cp->minor;
2254
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002255 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002256 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2257 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002258 goto unlock;
2259 }
2260
Johan Hedberg890ea892013-03-15 17:06:52 -05002261 hci_req_init(&req, hdev);
2262
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002263 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002264 hci_dev_unlock(hdev);
2265 cancel_delayed_work_sync(&hdev->service_cache);
2266 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002267 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002268 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002269
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002270 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002271
Johan Hedberg92da6092013-03-15 17:06:55 -05002272 err = hci_req_run(&req, set_class_complete);
2273 if (err < 0) {
2274 if (err != -ENODATA)
2275 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002276
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002277 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2278 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002279 goto unlock;
2280 }
2281
2282 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002283 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002284 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002285 goto unlock;
2286 }
2287
2288 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002289
Johan Hedbergb5235a62012-02-21 14:32:24 +02002290unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002291 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002292 return err;
2293}
2294
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002295static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002296 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002298 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002299 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2300 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002301 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002302 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002303 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002304
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002305 BT_DBG("request for %s", hdev->name);
2306
2307 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2309 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002310
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002311 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002312 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002313 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2314 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002315 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2316 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002317 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002318
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002319 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002320 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002321 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2322 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002323 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2324 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002325 }
2326
Johan Hedberg4ae14302013-01-20 14:27:13 +02002327 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002330
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002331 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002332 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002334 for (i = 0; i < key_count; i++) {
2335 struct mgmt_link_key_info *key = &cp->keys[i];
2336
Marcel Holtmann8e991132014-01-10 02:07:25 -08002337 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002338 return mgmt_cmd_status(sk, hdev->id,
2339 MGMT_OP_LOAD_LINK_KEYS,
2340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002341 }
2342
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002343 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
2345 hci_link_keys_clear(hdev);
2346
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002347 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002348 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002349 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002350 changed = hci_dev_test_and_clear_flag(hdev,
2351 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002352
2353 if (changed)
2354 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002355
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002356 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002357 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Alain Michaud600a8742020-01-07 00:43:17 +00002359 if (hci_is_blocked_key(hdev,
2360 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2361 key->val)) {
2362 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2363 &key->addr.bdaddr);
2364 continue;
2365 }
2366
Johan Hedberg58e92932014-06-24 14:00:26 +03002367 /* Always ignore debug keys and require a new pairing if
2368 * the user wants to use them.
2369 */
2370 if (key->type == HCI_LK_DEBUG_COMBINATION)
2371 continue;
2372
Johan Hedberg7652ff62014-06-24 13:15:49 +03002373 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2374 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375 }
2376
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002377 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002378
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002379 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002381 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002382}
2383
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002384static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002385 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002386{
2387 struct mgmt_ev_device_unpaired ev;
2388
2389 bacpy(&ev.addr.bdaddr, bdaddr);
2390 ev.addr.type = addr_type;
2391
2392 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002393 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002394}
2395
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002398{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002399 struct mgmt_cp_unpair_device *cp = data;
2400 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002401 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002402 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002403 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002404 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002405 int err;
2406
Johan Hedberga8a1d192011-11-10 15:54:38 +02002407 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002408 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2409 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002410
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002411 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002412 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2413 MGMT_STATUS_INVALID_PARAMS,
2414 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002415
Johan Hedberg118da702013-01-20 14:27:20 +02002416 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002417 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2418 MGMT_STATUS_INVALID_PARAMS,
2419 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002420
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002421 hci_dev_lock(hdev);
2422
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002423 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002424 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2425 MGMT_STATUS_NOT_POWERED, &rp,
2426 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002427 goto unlock;
2428 }
2429
Johan Hedberge0b2b272014-02-18 17:14:31 +02002430 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002431 /* If disconnection is requested, then look up the
2432 * connection. If the remote device is connected, it
2433 * will be later used to terminate the link.
2434 *
2435 * Setting it to NULL explicitly will cause no
2436 * termination of the link.
2437 */
2438 if (cp->disconnect)
2439 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2440 &cp->addr.bdaddr);
2441 else
2442 conn = NULL;
2443
Johan Hedberg124f6e32012-02-09 13:50:12 +02002444 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002445 if (err < 0) {
2446 err = mgmt_cmd_complete(sk, hdev->id,
2447 MGMT_OP_UNPAIR_DEVICE,
2448 MGMT_STATUS_NOT_PAIRED, &rp,
2449 sizeof(rp));
2450 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002451 }
2452
Johan Hedbergec182f02015-10-21 18:03:03 +03002453 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002454 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002455
Johan Hedbergec182f02015-10-21 18:03:03 +03002456 /* LE address type */
2457 addr_type = le_addr_type(cp->addr.type);
2458
Matias Karhumaacb28c302018-09-26 09:13:46 +03002459 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2460 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002461 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002462 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2463 MGMT_STATUS_NOT_PAIRED, &rp,
2464 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002465 goto unlock;
2466 }
2467
Johan Hedbergec182f02015-10-21 18:03:03 +03002468 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2469 if (!conn) {
2470 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2471 goto done;
2472 }
2473
Johan Hedbergc81d5552015-10-22 09:38:35 +03002474
Johan Hedbergec182f02015-10-21 18:03:03 +03002475 /* Defer clearing up the connection parameters until closing to
2476 * give a chance of keeping them if a repairing happens.
2477 */
2478 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2479
Johan Hedbergfc643612015-10-22 09:38:31 +03002480 /* Disable auto-connection parameters if present */
2481 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2482 if (params) {
2483 if (params->explicit_connect)
2484 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2485 else
2486 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2487 }
2488
Johan Hedbergec182f02015-10-21 18:03:03 +03002489 /* If disconnection is not requested, then clear the connection
2490 * variable so that the link is not terminated.
2491 */
2492 if (!cp->disconnect)
2493 conn = NULL;
2494
2495done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002496 /* If the connection variable is set, then termination of the
2497 * link is requested.
2498 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002499 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002500 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2501 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002502 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002503 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002504 }
2505
Johan Hedberg124f6e32012-02-09 13:50:12 +02002506 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002508 if (!cmd) {
2509 err = -ENOMEM;
2510 goto unlock;
2511 }
2512
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002513 cmd->cmd_complete = addr_cmd_complete;
2514
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002515 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002516 if (err < 0)
2517 mgmt_pending_remove(cmd);
2518
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002519unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002520 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002521 return err;
2522}
2523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002525 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002527 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002528 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002529 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002530 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531 int err;
2532
2533 BT_DBG("");
2534
Johan Hedberg06a63b12013-01-20 14:27:21 +02002535 memset(&rp, 0, sizeof(rp));
2536 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2537 rp.addr.type = cp->addr.type;
2538
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002539 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002540 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2541 MGMT_STATUS_INVALID_PARAMS,
2542 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002544 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002545
2546 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002547 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2548 MGMT_STATUS_NOT_POWERED, &rp,
2549 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002550 goto failed;
2551 }
2552
Johan Hedberg333ae952015-03-17 13:48:47 +02002553 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002554 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2555 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002556 goto failed;
2557 }
2558
Andre Guedes591f47f2012-04-24 21:02:49 -03002559 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002560 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2561 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002562 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002563 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2564 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002565
Vishal Agarwalf9607272012-06-13 05:32:43 +05302566 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002567 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2568 MGMT_STATUS_NOT_CONNECTED, &rp,
2569 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570 goto failed;
2571 }
2572
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002573 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002574 if (!cmd) {
2575 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002577 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002578
Johan Hedbergf5818c22014-12-05 13:36:02 +02002579 cmd->cmd_complete = generic_cmd_complete;
2580
Johan Hedberge3f2f922014-08-18 20:33:33 +03002581 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002582 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002583 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002584
2585failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002586 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002587 return err;
2588}
2589
Andre Guedes57c14772012-04-24 21:02:50 -03002590static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002591{
2592 switch (link_type) {
2593 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002594 switch (addr_type) {
2595 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002596 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002597
Johan Hedberg48264f02011-11-09 13:58:58 +02002598 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002599 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002600 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002601 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002602
Johan Hedberg4c659c32011-11-07 23:13:39 +02002603 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002604 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002605 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002606 }
2607}
2608
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2610 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002611{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002612 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002613 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002614 int err;
2615 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002616
2617 BT_DBG("");
2618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002620
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002621 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002622 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2623 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002624 goto unlock;
2625 }
2626
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002627 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002628 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2629 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002630 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002631 }
2632
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002633 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002634 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002635 err = -ENOMEM;
2636 goto unlock;
2637 }
2638
Johan Hedberg2784eb42011-01-21 13:56:35 +02002639 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002640 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002641 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2642 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002643 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002644 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002645 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002646 continue;
2647 i++;
2648 }
2649
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002650 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002651
Johan Hedberg4c659c32011-11-07 23:13:39 +02002652 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002653 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002654 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002655
Johan Hedberga38528f2011-01-22 06:46:43 +02002656 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002657
2658unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002659 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002660 return err;
2661}
2662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002663static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002665{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002666 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002667 int err;
2668
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002669 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002670 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002671 if (!cmd)
2672 return -ENOMEM;
2673
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002674 cmd->cmd_complete = addr_cmd_complete;
2675
Johan Hedbergd8457692012-02-17 14:24:57 +02002676 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002678 if (err < 0)
2679 mgmt_pending_remove(cmd);
2680
2681 return err;
2682}
2683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002684static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002686{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002687 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002689 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002690 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002691 int err;
2692
2693 BT_DBG("");
2694
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002695 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002696
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002697 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002698 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2699 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002700 goto failed;
2701 }
2702
Johan Hedbergd8457692012-02-17 14:24:57 +02002703 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002704 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002705 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2706 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002707 goto failed;
2708 }
2709
2710 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002711 struct mgmt_cp_pin_code_neg_reply ncp;
2712
2713 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002714
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002715 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002718 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002719 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2720 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002721
2722 goto failed;
2723 }
2724
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002725 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002726 if (!cmd) {
2727 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002729 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002731 cmd->cmd_complete = addr_cmd_complete;
2732
Johan Hedbergd8457692012-02-17 14:24:57 +02002733 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002734 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002735 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002736
2737 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2738 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002739 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002740
2741failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002742 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002743 return err;
2744}
2745
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002746static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2747 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002749 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002750
2751 BT_DBG("");
2752
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002753 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002754 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002757 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002758
2759 hdev->io_capability = cp->io_capability;
2760
2761 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002762 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002764 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002765
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002766 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2767 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002768}
2769
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002770static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002771{
2772 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002773 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002774
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002775 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002776 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2777 continue;
2778
Johan Hedberge9a416b2011-02-19 12:05:56 -03002779 if (cmd->user_data != conn)
2780 continue;
2781
2782 return cmd;
2783 }
2784
2785 return NULL;
2786}
2787
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002788static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002789{
2790 struct mgmt_rp_pair_device rp;
2791 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002792 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002794 bacpy(&rp.addr.bdaddr, &conn->dst);
2795 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002796
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002797 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2798 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799
2800 /* So we don't get further callbacks for this connection */
2801 conn->connect_cfm_cb = NULL;
2802 conn->security_cfm_cb = NULL;
2803 conn->disconn_cfm_cb = NULL;
2804
David Herrmann76a68ba2013-04-06 20:28:37 +02002805 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002806
2807 /* The device is paired so there is no need to remove
2808 * its connection parameters anymore.
2809 */
2810 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002811
2812 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002813
2814 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002815}
2816
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002817void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2818{
2819 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002820 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002821
2822 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002823 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002824 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002825 mgmt_pending_remove(cmd);
2826 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002827}
2828
Johan Hedberge9a416b2011-02-19 12:05:56 -03002829static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2830{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002831 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002832
2833 BT_DBG("status %u", status);
2834
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002835 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002836 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002837 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002838 return;
2839 }
2840
2841 cmd->cmd_complete(cmd, mgmt_status(status));
2842 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843}
2844
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002845static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302846{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002847 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302848
2849 BT_DBG("status %u", status);
2850
2851 if (!status)
2852 return;
2853
2854 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002855 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302856 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002857 return;
2858 }
2859
2860 cmd->cmd_complete(cmd, mgmt_status(status));
2861 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302862}
2863
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002864static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002865 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002866{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002867 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002868 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002869 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002870 u8 sec_level, auth_type;
2871 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872 int err;
2873
2874 BT_DBG("");
2875
Szymon Jancf950a30e2013-01-18 12:48:07 +01002876 memset(&rp, 0, sizeof(rp));
2877 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2878 rp.addr.type = cp->addr.type;
2879
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002880 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002881 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2882 MGMT_STATUS_INVALID_PARAMS,
2883 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002884
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002885 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002886 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2887 MGMT_STATUS_INVALID_PARAMS,
2888 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002890 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002891
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002892 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002893 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2894 MGMT_STATUS_NOT_POWERED, &rp,
2895 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002896 goto unlock;
2897 }
2898
Johan Hedberg55e76b32015-03-10 22:34:40 +02002899 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2900 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2901 MGMT_STATUS_ALREADY_PAIRED, &rp,
2902 sizeof(rp));
2903 goto unlock;
2904 }
2905
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002906 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002907 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002908
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002909 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002910 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2911 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002912 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002913 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002914 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002915
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002916 /* When pairing a new device, it is expected to remember
2917 * this device for future connections. Adding the connection
2918 * parameter information ahead of time allows tracking
2919 * of the slave preferred values and will speed up any
2920 * further connection establishment.
2921 *
2922 * If connection parameters already exist, then they
2923 * will be kept and this function does nothing.
2924 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002925 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2926
2927 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2928 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002929
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002930 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2931 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002932 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002933 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002934
Ville Tervo30e76272011-02-22 16:10:53 -03002935 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002936 int status;
2937
2938 if (PTR_ERR(conn) == -EBUSY)
2939 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002940 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2941 status = MGMT_STATUS_NOT_SUPPORTED;
2942 else if (PTR_ERR(conn) == -ECONNREFUSED)
2943 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002944 else
2945 status = MGMT_STATUS_CONNECT_FAILED;
2946
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002947 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2948 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002949 goto unlock;
2950 }
2951
2952 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002953 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002954 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2955 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002956 goto unlock;
2957 }
2958
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002959 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002960 if (!cmd) {
2961 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002962 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002963 goto unlock;
2964 }
2965
Johan Hedberg04ab2742014-12-05 13:36:04 +02002966 cmd->cmd_complete = pairing_complete;
2967
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002968 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002969 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002970 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002971 conn->security_cfm_cb = pairing_complete_cb;
2972 conn->disconn_cfm_cb = pairing_complete_cb;
2973 } else {
2974 conn->connect_cfm_cb = le_pairing_complete_cb;
2975 conn->security_cfm_cb = le_pairing_complete_cb;
2976 conn->disconn_cfm_cb = le_pairing_complete_cb;
2977 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002978
Johan Hedberge9a416b2011-02-19 12:05:56 -03002979 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002980 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002981
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002982 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002983 hci_conn_security(conn, sec_level, auth_type, true)) {
2984 cmd->cmd_complete(cmd, 0);
2985 mgmt_pending_remove(cmd);
2986 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002987
2988 err = 0;
2989
2990unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002992 return err;
2993}
2994
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2996 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002997{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002998 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002999 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003000 struct hci_conn *conn;
3001 int err;
3002
3003 BT_DBG("");
3004
Johan Hedberg28424702012-02-02 04:02:29 +02003005 hci_dev_lock(hdev);
3006
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003007 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003008 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3009 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003010 goto unlock;
3011 }
3012
Johan Hedberg333ae952015-03-17 13:48:47 +02003013 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003014 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003015 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3016 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003017 goto unlock;
3018 }
3019
3020 conn = cmd->user_data;
3021
3022 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003023 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3024 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003025 goto unlock;
3026 }
3027
Johan Hedberga511b352014-12-11 21:45:45 +02003028 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3029 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003030
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003031 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3032 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003033unlock:
3034 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003035 return err;
3036}
3037
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003038static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003039 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003041{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003042 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003043 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003044 int err;
3045
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003046 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003047
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003048 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003049 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3050 MGMT_STATUS_NOT_POWERED, addr,
3051 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003052 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003053 }
3054
Johan Hedberg1707c602013-03-15 17:07:15 -05003055 if (addr->type == BDADDR_BREDR)
3056 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003057 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003058 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3059 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003060
Johan Hedberg272d90d2012-02-09 15:26:12 +02003061 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003062 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3063 MGMT_STATUS_NOT_CONNECTED, addr,
3064 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003065 goto done;
3066 }
3067
Johan Hedberg1707c602013-03-15 17:07:15 -05003068 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003069 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003070 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003071 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3072 MGMT_STATUS_SUCCESS, addr,
3073 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003074 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003075 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3076 MGMT_STATUS_FAILED, addr,
3077 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003078
Brian Gix47c15e22011-11-16 13:53:14 -08003079 goto done;
3080 }
3081
Johan Hedberg1707c602013-03-15 17:07:15 -05003082 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003083 if (!cmd) {
3084 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003085 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003086 }
3087
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003088 cmd->cmd_complete = addr_cmd_complete;
3089
Brian Gix0df4c182011-11-16 13:53:13 -08003090 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003091 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3092 struct hci_cp_user_passkey_reply cp;
3093
Johan Hedberg1707c602013-03-15 17:07:15 -05003094 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003095 cp.passkey = passkey;
3096 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3097 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003098 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3099 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003100
Johan Hedberga664b5b2011-02-19 12:06:02 -03003101 if (err < 0)
3102 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003103
Brian Gix0df4c182011-11-16 13:53:13 -08003104done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003105 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003106 return err;
3107}
3108
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303109static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3110 void *data, u16 len)
3111{
3112 struct mgmt_cp_pin_code_neg_reply *cp = data;
3113
3114 BT_DBG("");
3115
Johan Hedberg1707c602013-03-15 17:07:15 -05003116 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303117 MGMT_OP_PIN_CODE_NEG_REPLY,
3118 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3119}
3120
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3122 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003123{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003124 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003125
3126 BT_DBG("");
3127
3128 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003129 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3130 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003131
Johan Hedberg1707c602013-03-15 17:07:15 -05003132 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003133 MGMT_OP_USER_CONFIRM_REPLY,
3134 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003135}
3136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003137static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003139{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003140 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003141
3142 BT_DBG("");
3143
Johan Hedberg1707c602013-03-15 17:07:15 -05003144 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3146 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003147}
3148
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003149static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3150 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003151{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003152 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003153
3154 BT_DBG("");
3155
Johan Hedberg1707c602013-03-15 17:07:15 -05003156 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 MGMT_OP_USER_PASSKEY_REPLY,
3158 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003159}
3160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003161static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003164 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003165
3166 BT_DBG("");
3167
Johan Hedberg1707c602013-03-15 17:07:15 -05003168 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3170 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003171}
3172
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003173static void adv_expire(struct hci_dev *hdev, u32 flags)
3174{
3175 struct adv_info *adv_instance;
3176 struct hci_request req;
3177 int err;
3178
3179 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3180 if (!adv_instance)
3181 return;
3182
3183 /* stop if current instance doesn't need to be changed */
3184 if (!(adv_instance->flags & flags))
3185 return;
3186
3187 cancel_adv_timeout(hdev);
3188
3189 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3190 if (!adv_instance)
3191 return;
3192
3193 hci_req_init(&req, hdev);
3194 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3195 true);
3196 if (err)
3197 return;
3198
3199 hci_req_run(&req, NULL);
3200}
3201
Marcel Holtmann1904a852015-01-11 13:50:44 -08003202static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003203{
3204 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003205 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003206
3207 BT_DBG("status 0x%02x", status);
3208
3209 hci_dev_lock(hdev);
3210
Johan Hedberg333ae952015-03-17 13:48:47 +02003211 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003212 if (!cmd)
3213 goto unlock;
3214
3215 cp = cmd->param;
3216
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003217 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003218 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3219 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003220 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003221 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3222 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003223
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003224 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3225 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3226 }
3227
Johan Hedberg13928972013-03-15 17:07:00 -05003228 mgmt_pending_remove(cmd);
3229
3230unlock:
3231 hci_dev_unlock(hdev);
3232}
3233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003234static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003236{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003237 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003238 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003239 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003240 int err;
3241
3242 BT_DBG("");
3243
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003244 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003245
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003246 /* If the old values are the same as the new ones just return a
3247 * direct command complete event.
3248 */
3249 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3250 !memcmp(hdev->short_name, cp->short_name,
3251 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003252 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3253 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003254 goto failed;
3255 }
3256
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003257 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003258
Johan Hedbergb5235a62012-02-21 14:32:24 +02003259 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003260 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003261
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3263 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003264 if (err < 0)
3265 goto failed;
3266
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003267 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3268 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003269 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003270
Johan Hedbergb5235a62012-02-21 14:32:24 +02003271 goto failed;
3272 }
3273
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003274 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003275 if (!cmd) {
3276 err = -ENOMEM;
3277 goto failed;
3278 }
3279
Johan Hedberg13928972013-03-15 17:07:00 -05003280 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3281
Johan Hedberg890ea892013-03-15 17:06:52 -05003282 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003283
3284 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003285 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003286 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003287 }
3288
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003289 /* The name is stored in the scan response data and so
3290 * no need to udpate the advertising data here.
3291 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003292 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003293 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003294
Johan Hedberg13928972013-03-15 17:07:00 -05003295 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003296 if (err < 0)
3297 mgmt_pending_remove(cmd);
3298
3299failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003300 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003301 return err;
3302}
3303
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003304static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3305 u16 len)
3306{
3307 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003308 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003309 int err;
3310
3311 BT_DBG("");
3312
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003313 if (!lmp_le_capable(hdev))
3314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3315 MGMT_STATUS_NOT_SUPPORTED);
3316
Alain Michaud6613bab2020-01-22 19:47:44 +00003317 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003318
3319 hci_dev_lock(hdev);
3320
Alain Michaud6613bab2020-01-22 19:47:44 +00003321 if (hdev->appearance != appearance) {
3322 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003323
3324 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3325 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003326
3327 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003328 }
3329
3330 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3331 0);
3332
3333 hci_dev_unlock(hdev);
3334
3335 return err;
3336}
3337
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303338static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3339 void *data, u16 len)
3340{
3341 struct mgmt_rp_get_phy_confguration rp;
3342
3343 BT_DBG("sock %p %s", sk, hdev->name);
3344
3345 hci_dev_lock(hdev);
3346
3347 memset(&rp, 0, sizeof(rp));
3348
3349 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3350 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3351 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3352
3353 hci_dev_unlock(hdev);
3354
3355 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3356 &rp, sizeof(rp));
3357}
3358
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303359int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3360{
3361 struct mgmt_ev_phy_configuration_changed ev;
3362
3363 memset(&ev, 0, sizeof(ev));
3364
3365 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3366
3367 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3368 sizeof(ev), skip);
3369}
3370
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303371static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3372 u16 opcode, struct sk_buff *skb)
3373{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303374 struct mgmt_pending_cmd *cmd;
3375
3376 BT_DBG("status 0x%02x", status);
3377
3378 hci_dev_lock(hdev);
3379
3380 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3381 if (!cmd)
3382 goto unlock;
3383
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303384 if (status) {
3385 mgmt_cmd_status(cmd->sk, hdev->id,
3386 MGMT_OP_SET_PHY_CONFIGURATION,
3387 mgmt_status(status));
3388 } else {
3389 mgmt_cmd_complete(cmd->sk, hdev->id,
3390 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3391 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303392
3393 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303394 }
3395
3396 mgmt_pending_remove(cmd);
3397
3398unlock:
3399 hci_dev_unlock(hdev);
3400}
3401
3402static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3403 void *data, u16 len)
3404{
3405 struct mgmt_cp_set_phy_confguration *cp = data;
3406 struct hci_cp_le_set_default_phy cp_phy;
3407 struct mgmt_pending_cmd *cmd;
3408 struct hci_request req;
3409 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3410 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303411 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303412 int err;
3413
3414 BT_DBG("sock %p %s", sk, hdev->name);
3415
3416 configurable_phys = get_configurable_phys(hdev);
3417 supported_phys = get_supported_phys(hdev);
3418 selected_phys = __le32_to_cpu(cp->selected_phys);
3419
3420 if (selected_phys & ~supported_phys)
3421 return mgmt_cmd_status(sk, hdev->id,
3422 MGMT_OP_SET_PHY_CONFIGURATION,
3423 MGMT_STATUS_INVALID_PARAMS);
3424
3425 unconfigure_phys = supported_phys & ~configurable_phys;
3426
3427 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3428 return mgmt_cmd_status(sk, hdev->id,
3429 MGMT_OP_SET_PHY_CONFIGURATION,
3430 MGMT_STATUS_INVALID_PARAMS);
3431
3432 if (selected_phys == get_selected_phys(hdev))
3433 return mgmt_cmd_complete(sk, hdev->id,
3434 MGMT_OP_SET_PHY_CONFIGURATION,
3435 0, NULL, 0);
3436
3437 hci_dev_lock(hdev);
3438
3439 if (!hdev_is_powered(hdev)) {
3440 err = mgmt_cmd_status(sk, hdev->id,
3441 MGMT_OP_SET_PHY_CONFIGURATION,
3442 MGMT_STATUS_REJECTED);
3443 goto unlock;
3444 }
3445
3446 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3447 err = mgmt_cmd_status(sk, hdev->id,
3448 MGMT_OP_SET_PHY_CONFIGURATION,
3449 MGMT_STATUS_BUSY);
3450 goto unlock;
3451 }
3452
3453 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3454 pkt_type |= (HCI_DH3 | HCI_DM3);
3455 else
3456 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3457
3458 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3459 pkt_type |= (HCI_DH5 | HCI_DM5);
3460 else
3461 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3462
3463 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3464 pkt_type &= ~HCI_2DH1;
3465 else
3466 pkt_type |= HCI_2DH1;
3467
3468 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3469 pkt_type &= ~HCI_2DH3;
3470 else
3471 pkt_type |= HCI_2DH3;
3472
3473 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3474 pkt_type &= ~HCI_2DH5;
3475 else
3476 pkt_type |= HCI_2DH5;
3477
3478 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3479 pkt_type &= ~HCI_3DH1;
3480 else
3481 pkt_type |= HCI_3DH1;
3482
3483 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3484 pkt_type &= ~HCI_3DH3;
3485 else
3486 pkt_type |= HCI_3DH3;
3487
3488 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3489 pkt_type &= ~HCI_3DH5;
3490 else
3491 pkt_type |= HCI_3DH5;
3492
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303493 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303494 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303495 changed = true;
3496 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303497
3498 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3499 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303500 if (changed)
3501 mgmt_phy_configuration_changed(hdev, sk);
3502
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303503 err = mgmt_cmd_complete(sk, hdev->id,
3504 MGMT_OP_SET_PHY_CONFIGURATION,
3505 0, NULL, 0);
3506
3507 goto unlock;
3508 }
3509
3510 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3511 len);
3512 if (!cmd) {
3513 err = -ENOMEM;
3514 goto unlock;
3515 }
3516
3517 hci_req_init(&req, hdev);
3518
3519 memset(&cp_phy, 0, sizeof(cp_phy));
3520
3521 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3522 cp_phy.all_phys |= 0x01;
3523
3524 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3525 cp_phy.all_phys |= 0x02;
3526
3527 if (selected_phys & MGMT_PHY_LE_1M_TX)
3528 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3529
3530 if (selected_phys & MGMT_PHY_LE_2M_TX)
3531 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3532
3533 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3534 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3535
3536 if (selected_phys & MGMT_PHY_LE_1M_RX)
3537 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3538
3539 if (selected_phys & MGMT_PHY_LE_2M_RX)
3540 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3541
3542 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3543 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3544
3545 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3546
3547 err = hci_req_run_skb(&req, set_default_phy_complete);
3548 if (err < 0)
3549 mgmt_pending_remove(cmd);
3550
3551unlock:
3552 hci_dev_unlock(hdev);
3553
3554 return err;
3555}
3556
Alain Michaud600a8742020-01-07 00:43:17 +00003557static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3558 u16 len)
3559{
3560 int err = MGMT_STATUS_SUCCESS;
3561 struct mgmt_cp_set_blocked_keys *keys = data;
3562 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3563 sizeof(struct mgmt_blocked_key_info));
3564 u16 key_count, expected_len;
3565 int i;
3566
3567 BT_DBG("request for %s", hdev->name);
3568
3569 key_count = __le16_to_cpu(keys->key_count);
3570 if (key_count > max_key_count) {
3571 bt_dev_err(hdev, "too big key_count value %u", key_count);
3572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3573 MGMT_STATUS_INVALID_PARAMS);
3574 }
3575
3576 expected_len = struct_size(keys, keys, key_count);
3577 if (expected_len != len) {
3578 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3579 expected_len, len);
3580 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3581 MGMT_STATUS_INVALID_PARAMS);
3582 }
3583
3584 hci_dev_lock(hdev);
3585
3586 hci_blocked_keys_clear(hdev);
3587
3588 for (i = 0; i < keys->key_count; ++i) {
3589 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3590
3591 if (!b) {
3592 err = MGMT_STATUS_NO_RESOURCES;
3593 break;
3594 }
3595
3596 b->type = keys->keys[i].type;
3597 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3598 list_add_rcu(&b->list, &hdev->blocked_keys);
3599 }
3600 hci_dev_unlock(hdev);
3601
3602 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3603 err, NULL, 0);
3604}
3605
Alain Michaud00bce3f2020-03-05 16:14:59 +00003606static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3607 void *data, u16 len)
3608{
3609 struct mgmt_mode *cp = data;
3610 int err;
3611 bool changed = false;
3612
3613 BT_DBG("request for %s", hdev->name);
3614
3615 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3616 return mgmt_cmd_status(sk, hdev->id,
3617 MGMT_OP_SET_WIDEBAND_SPEECH,
3618 MGMT_STATUS_NOT_SUPPORTED);
3619
3620 if (cp->val != 0x00 && cp->val != 0x01)
3621 return mgmt_cmd_status(sk, hdev->id,
3622 MGMT_OP_SET_WIDEBAND_SPEECH,
3623 MGMT_STATUS_INVALID_PARAMS);
3624
3625 hci_dev_lock(hdev);
3626
3627 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3628 err = mgmt_cmd_status(sk, hdev->id,
3629 MGMT_OP_SET_WIDEBAND_SPEECH,
3630 MGMT_STATUS_BUSY);
3631 goto unlock;
3632 }
3633
3634 if (hdev_is_powered(hdev) &&
3635 !!cp->val != hci_dev_test_flag(hdev,
3636 HCI_WIDEBAND_SPEECH_ENABLED)) {
3637 err = mgmt_cmd_status(sk, hdev->id,
3638 MGMT_OP_SET_WIDEBAND_SPEECH,
3639 MGMT_STATUS_REJECTED);
3640 goto unlock;
3641 }
3642
3643 if (cp->val)
3644 changed = !hci_dev_test_and_set_flag(hdev,
3645 HCI_WIDEBAND_SPEECH_ENABLED);
3646 else
3647 changed = hci_dev_test_and_clear_flag(hdev,
3648 HCI_WIDEBAND_SPEECH_ENABLED);
3649
3650 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3651 if (err < 0)
3652 goto unlock;
3653
3654 if (changed)
3655 err = new_settings(hdev, sk);
3656
3657unlock:
3658 hci_dev_unlock(hdev);
3659 return err;
3660}
3661
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003662static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3663 u16 opcode, struct sk_buff *skb)
3664{
3665 struct mgmt_rp_read_local_oob_data mgmt_rp;
3666 size_t rp_size = sizeof(mgmt_rp);
3667 struct mgmt_pending_cmd *cmd;
3668
3669 BT_DBG("%s status %u", hdev->name, status);
3670
3671 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3672 if (!cmd)
3673 return;
3674
3675 if (status || !skb) {
3676 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3677 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3678 goto remove;
3679 }
3680
3681 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3682
3683 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3684 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3685
3686 if (skb->len < sizeof(*rp)) {
3687 mgmt_cmd_status(cmd->sk, hdev->id,
3688 MGMT_OP_READ_LOCAL_OOB_DATA,
3689 MGMT_STATUS_FAILED);
3690 goto remove;
3691 }
3692
3693 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3694 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3695
3696 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3697 } else {
3698 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3699
3700 if (skb->len < sizeof(*rp)) {
3701 mgmt_cmd_status(cmd->sk, hdev->id,
3702 MGMT_OP_READ_LOCAL_OOB_DATA,
3703 MGMT_STATUS_FAILED);
3704 goto remove;
3705 }
3706
3707 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3708 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3709
3710 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3711 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3712 }
3713
3714 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3715 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3716
3717remove:
3718 mgmt_pending_remove(cmd);
3719}
3720
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003721static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003722 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003723{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003724 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003725 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003726 int err;
3727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003728 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003729
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003730 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003731
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003732 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003733 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3734 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003735 goto unlock;
3736 }
3737
Andre Guedes9a1a1992012-07-24 15:03:48 -03003738 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003739 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3740 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003741 goto unlock;
3742 }
3743
Johan Hedberg333ae952015-03-17 13:48:47 +02003744 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003745 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3746 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003747 goto unlock;
3748 }
3749
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003750 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003751 if (!cmd) {
3752 err = -ENOMEM;
3753 goto unlock;
3754 }
3755
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003756 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003757
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003758 if (bredr_sc_enabled(hdev))
3759 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3760 else
3761 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3762
3763 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003764 if (err < 0)
3765 mgmt_pending_remove(cmd);
3766
3767unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003768 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003769 return err;
3770}
3771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003772static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003773 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003774{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003775 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003776 int err;
3777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003778 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003779
Johan Hedberg5d57e792015-01-23 10:10:38 +02003780 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003781 return mgmt_cmd_complete(sk, hdev->id,
3782 MGMT_OP_ADD_REMOTE_OOB_DATA,
3783 MGMT_STATUS_INVALID_PARAMS,
3784 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003785
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003786 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003787
Marcel Holtmannec109112014-01-10 02:07:30 -08003788 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3789 struct mgmt_cp_add_remote_oob_data *cp = data;
3790 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003791
Johan Hedbergc19a4952014-11-17 20:52:19 +02003792 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003793 err = mgmt_cmd_complete(sk, hdev->id,
3794 MGMT_OP_ADD_REMOTE_OOB_DATA,
3795 MGMT_STATUS_INVALID_PARAMS,
3796 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003797 goto unlock;
3798 }
3799
Marcel Holtmannec109112014-01-10 02:07:30 -08003800 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003801 cp->addr.type, cp->hash,
3802 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003803 if (err < 0)
3804 status = MGMT_STATUS_FAILED;
3805 else
3806 status = MGMT_STATUS_SUCCESS;
3807
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003808 err = mgmt_cmd_complete(sk, hdev->id,
3809 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3810 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003811 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3812 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003813 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003814 u8 status;
3815
Johan Hedberg86df9202014-10-26 20:52:27 +01003816 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003817 /* Enforce zero-valued 192-bit parameters as
3818 * long as legacy SMP OOB isn't implemented.
3819 */
3820 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3821 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003822 err = mgmt_cmd_complete(sk, hdev->id,
3823 MGMT_OP_ADD_REMOTE_OOB_DATA,
3824 MGMT_STATUS_INVALID_PARAMS,
3825 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003826 goto unlock;
3827 }
3828
Johan Hedberg86df9202014-10-26 20:52:27 +01003829 rand192 = NULL;
3830 hash192 = NULL;
3831 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003832 /* In case one of the P-192 values is set to zero,
3833 * then just disable OOB data for P-192.
3834 */
3835 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3836 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3837 rand192 = NULL;
3838 hash192 = NULL;
3839 } else {
3840 rand192 = cp->rand192;
3841 hash192 = cp->hash192;
3842 }
3843 }
3844
3845 /* In case one of the P-256 values is set to zero, then just
3846 * disable OOB data for P-256.
3847 */
3848 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3849 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3850 rand256 = NULL;
3851 hash256 = NULL;
3852 } else {
3853 rand256 = cp->rand256;
3854 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003855 }
3856
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003857 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003858 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003859 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003860 if (err < 0)
3861 status = MGMT_STATUS_FAILED;
3862 else
3863 status = MGMT_STATUS_SUCCESS;
3864
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003865 err = mgmt_cmd_complete(sk, hdev->id,
3866 MGMT_OP_ADD_REMOTE_OOB_DATA,
3867 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003868 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003869 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3870 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003871 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3872 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003873 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003874
Johan Hedbergc19a4952014-11-17 20:52:19 +02003875unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003876 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003877 return err;
3878}
3879
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003880static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003881 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003883 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003884 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003885 int err;
3886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003887 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003888
Johan Hedbergc19a4952014-11-17 20:52:19 +02003889 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003890 return mgmt_cmd_complete(sk, hdev->id,
3891 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3892 MGMT_STATUS_INVALID_PARAMS,
3893 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003894
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003895 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003896
Johan Hedbergeedbd582014-11-15 09:34:23 +02003897 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3898 hci_remote_oob_data_clear(hdev);
3899 status = MGMT_STATUS_SUCCESS;
3900 goto done;
3901 }
3902
Johan Hedberg6928a922014-10-26 20:46:09 +01003903 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003904 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003905 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003906 else
Szymon Janca6785be2012-12-13 15:11:21 +01003907 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003908
Johan Hedbergeedbd582014-11-15 09:34:23 +02003909done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003910 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3911 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003913 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003914 return err;
3915}
3916
Johan Hedberge68f0722015-11-11 08:30:30 +02003917void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003918{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003919 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003920
Andre Guedes7c307722013-04-30 15:29:28 -03003921 BT_DBG("status %d", status);
3922
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003923 hci_dev_lock(hdev);
3924
Johan Hedberg333ae952015-03-17 13:48:47 +02003925 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003926 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003927 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003928
Johan Hedberg78b781c2016-01-05 13:19:32 +02003929 if (!cmd)
3930 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3931
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003932 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003933 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003934 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003935 }
3936
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003937 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07003938
3939 /* Handle suspend notifier */
3940 if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
3941 hdev->suspend_tasks)) {
3942 bt_dev_dbg(hdev, "Unpaused discovery");
3943 wake_up(&hdev->suspend_wait_q);
3944 }
Andre Guedes7c307722013-04-30 15:29:28 -03003945}
3946
Johan Hedberg591752a2015-11-11 08:11:24 +02003947static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3948 uint8_t *mgmt_status)
3949{
3950 switch (type) {
3951 case DISCOV_TYPE_LE:
3952 *mgmt_status = mgmt_le_support(hdev);
3953 if (*mgmt_status)
3954 return false;
3955 break;
3956 case DISCOV_TYPE_INTERLEAVED:
3957 *mgmt_status = mgmt_le_support(hdev);
3958 if (*mgmt_status)
3959 return false;
3960 /* Intentional fall-through */
3961 case DISCOV_TYPE_BREDR:
3962 *mgmt_status = mgmt_bredr_support(hdev);
3963 if (*mgmt_status)
3964 return false;
3965 break;
3966 default:
3967 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3968 return false;
3969 }
3970
3971 return true;
3972}
3973
Johan Hedberg78b781c2016-01-05 13:19:32 +02003974static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3975 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003976{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003977 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003978 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003979 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003980 int err;
3981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003982 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003983
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003984 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003985
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003986 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003987 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003988 MGMT_STATUS_NOT_POWERED,
3989 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003990 goto failed;
3991 }
3992
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003993 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003994 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003995 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3996 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003997 goto failed;
3998 }
3999
Johan Hedberg591752a2015-11-11 08:11:24 +02004000 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02004001 err = mgmt_cmd_complete(sk, hdev->id, op, status,
4002 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02004003 goto failed;
4004 }
4005
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004006 /* Can't start discovery when it is paused */
4007 if (hdev->discovery_paused) {
4008 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
4009 &cp->type, sizeof(cp->type));
4010 goto failed;
4011 }
4012
Marcel Holtmann22078802014-12-05 11:45:22 +01004013 /* Clear the discovery filter first to free any previously
4014 * allocated memory for the UUID list.
4015 */
4016 hci_discovery_filter_clear(hdev);
4017
Andre Guedes4aab14e2012-02-17 20:39:36 -03004018 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004019 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004020 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4021 hdev->discovery.limited = true;
4022 else
4023 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004024
Johan Hedberg78b781c2016-01-05 13:19:32 +02004025 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004026 if (!cmd) {
4027 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004028 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004029 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004030
Johan Hedberge68f0722015-11-11 08:30:30 +02004031 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004032
4033 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004034 queue_work(hdev->req_workqueue, &hdev->discov_update);
4035 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004036
4037failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004038 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004039 return err;
4040}
4041
Johan Hedberg78b781c2016-01-05 13:19:32 +02004042static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4043 void *data, u16 len)
4044{
4045 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4046 data, len);
4047}
4048
4049static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4050 void *data, u16 len)
4051{
4052 return start_discovery_internal(sk, hdev,
4053 MGMT_OP_START_LIMITED_DISCOVERY,
4054 data, len);
4055}
4056
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004057static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4058 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004059{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004060 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4061 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004062}
4063
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004064static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4065 void *data, u16 len)
4066{
4067 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004068 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004069 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4070 u16 uuid_count, expected_len;
4071 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004072 int err;
4073
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004074 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004075
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004076 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004077
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004078 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004079 err = mgmt_cmd_complete(sk, hdev->id,
4080 MGMT_OP_START_SERVICE_DISCOVERY,
4081 MGMT_STATUS_NOT_POWERED,
4082 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004083 goto failed;
4084 }
4085
4086 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004087 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004088 err = mgmt_cmd_complete(sk, hdev->id,
4089 MGMT_OP_START_SERVICE_DISCOVERY,
4090 MGMT_STATUS_BUSY, &cp->type,
4091 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004092 goto failed;
4093 }
4094
4095 uuid_count = __le16_to_cpu(cp->uuid_count);
4096 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004097 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4098 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004099 err = mgmt_cmd_complete(sk, hdev->id,
4100 MGMT_OP_START_SERVICE_DISCOVERY,
4101 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4102 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004103 goto failed;
4104 }
4105
4106 expected_len = sizeof(*cp) + uuid_count * 16;
4107 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004108 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4109 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004110 err = mgmt_cmd_complete(sk, hdev->id,
4111 MGMT_OP_START_SERVICE_DISCOVERY,
4112 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4113 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004114 goto failed;
4115 }
4116
Johan Hedberg591752a2015-11-11 08:11:24 +02004117 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4118 err = mgmt_cmd_complete(sk, hdev->id,
4119 MGMT_OP_START_SERVICE_DISCOVERY,
4120 status, &cp->type, sizeof(cp->type));
4121 goto failed;
4122 }
4123
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004124 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004125 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004126 if (!cmd) {
4127 err = -ENOMEM;
4128 goto failed;
4129 }
4130
Johan Hedberg2922a942014-12-05 13:36:06 +02004131 cmd->cmd_complete = service_discovery_cmd_complete;
4132
Marcel Holtmann22078802014-12-05 11:45:22 +01004133 /* Clear the discovery filter first to free any previously
4134 * allocated memory for the UUID list.
4135 */
4136 hci_discovery_filter_clear(hdev);
4137
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004138 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004139 hdev->discovery.type = cp->type;
4140 hdev->discovery.rssi = cp->rssi;
4141 hdev->discovery.uuid_count = uuid_count;
4142
4143 if (uuid_count > 0) {
4144 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4145 GFP_KERNEL);
4146 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004147 err = mgmt_cmd_complete(sk, hdev->id,
4148 MGMT_OP_START_SERVICE_DISCOVERY,
4149 MGMT_STATUS_FAILED,
4150 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004151 mgmt_pending_remove(cmd);
4152 goto failed;
4153 }
4154 }
4155
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004156 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004157 queue_work(hdev->req_workqueue, &hdev->discov_update);
4158 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004159
4160failed:
4161 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004162 return err;
4163}
4164
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004165void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004166{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004167 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004168
Andre Guedes0e05bba2013-04-30 15:29:33 -03004169 BT_DBG("status %d", status);
4170
4171 hci_dev_lock(hdev);
4172
Johan Hedberg333ae952015-03-17 13:48:47 +02004173 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004174 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004175 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004176 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004177 }
4178
Andre Guedes0e05bba2013-04-30 15:29:33 -03004179 hci_dev_unlock(hdev);
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004180
4181 /* Handle suspend notifier */
4182 if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
4183 bt_dev_dbg(hdev, "Paused discovery");
4184 wake_up(&hdev->suspend_wait_q);
4185 }
Andre Guedes0e05bba2013-04-30 15:29:33 -03004186}
4187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004188static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004189 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004190{
Johan Hedbergd9306502012-02-20 23:25:18 +02004191 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004192 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004193 int err;
4194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004195 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004197 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004198
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004199 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004200 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4201 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4202 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004203 goto unlock;
4204 }
4205
4206 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004207 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4208 MGMT_STATUS_INVALID_PARAMS,
4209 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004210 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004211 }
4212
Johan Hedberg2922a942014-12-05 13:36:06 +02004213 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004214 if (!cmd) {
4215 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004216 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004217 }
4218
Johan Hedberg2922a942014-12-05 13:36:06 +02004219 cmd->cmd_complete = generic_cmd_complete;
4220
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004221 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4222 queue_work(hdev->req_workqueue, &hdev->discov_update);
4223 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004224
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004225unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004226 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004227 return err;
4228}
4229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004230static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004231 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004232{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004233 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004234 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004235 int err;
4236
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004237 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004238
Johan Hedberg561aafb2012-01-04 13:31:59 +02004239 hci_dev_lock(hdev);
4240
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004241 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004242 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4243 MGMT_STATUS_FAILED, &cp->addr,
4244 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004245 goto failed;
4246 }
4247
Johan Hedberga198e7b2012-02-17 14:27:06 +02004248 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004249 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004250 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4251 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4252 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004253 goto failed;
4254 }
4255
4256 if (cp->name_known) {
4257 e->name_state = NAME_KNOWN;
4258 list_del(&e->list);
4259 } else {
4260 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004261 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004262 }
4263
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004264 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4265 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004266
4267failed:
4268 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004269 return err;
4270}
4271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004272static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004273 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004274{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004275 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004276 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004277 int err;
4278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004279 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004280
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004281 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004282 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4283 MGMT_STATUS_INVALID_PARAMS,
4284 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004285
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004286 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004287
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004288 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4289 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004290 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004291 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004292 goto done;
4293 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004294
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004295 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4296 sk);
4297 status = MGMT_STATUS_SUCCESS;
4298
4299done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004300 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4301 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004302
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004303 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004304
4305 return err;
4306}
4307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004308static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004310{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004311 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004312 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004313 int err;
4314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004315 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004316
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004317 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004318 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4319 MGMT_STATUS_INVALID_PARAMS,
4320 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004322 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004323
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004324 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4325 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004326 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004327 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004328 goto done;
4329 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004330
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004331 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4332 sk);
4333 status = MGMT_STATUS_SUCCESS;
4334
4335done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004336 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4337 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004339 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004340
4341 return err;
4342}
4343
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004344static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4345 u16 len)
4346{
4347 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004348 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004349 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004350 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004351
4352 BT_DBG("%s", hdev->name);
4353
Szymon Jancc72d4b82012-03-16 16:02:57 +01004354 source = __le16_to_cpu(cp->source);
4355
4356 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004357 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4358 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004359
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004360 hci_dev_lock(hdev);
4361
Szymon Jancc72d4b82012-03-16 16:02:57 +01004362 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004363 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4364 hdev->devid_product = __le16_to_cpu(cp->product);
4365 hdev->devid_version = __le16_to_cpu(cp->version);
4366
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004367 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4368 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004369
Johan Hedberg890ea892013-03-15 17:06:52 -05004370 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004371 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004372 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004373
4374 hci_dev_unlock(hdev);
4375
4376 return err;
4377}
4378
Arman Uguray24b4f382015-03-23 15:57:12 -07004379static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4380 u16 opcode)
4381{
4382 BT_DBG("status %d", status);
4383}
4384
Marcel Holtmann1904a852015-01-11 13:50:44 -08004385static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4386 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004387{
4388 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004389 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004390 u8 instance;
4391 struct adv_info *adv_instance;
4392 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004393
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304394 hci_dev_lock(hdev);
4395
Johan Hedberg4375f102013-09-25 13:26:10 +03004396 if (status) {
4397 u8 mgmt_err = mgmt_status(status);
4398
4399 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4400 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304401 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004402 }
4403
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004404 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004405 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004406 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004407 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004408
Johan Hedberg4375f102013-09-25 13:26:10 +03004409 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4410 &match);
4411
4412 new_settings(hdev, match.sk);
4413
4414 if (match.sk)
4415 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304416
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004417 /* Handle suspend notifier */
4418 if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
4419 hdev->suspend_tasks)) {
4420 bt_dev_dbg(hdev, "Paused advertising");
4421 wake_up(&hdev->suspend_wait_q);
4422 } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
4423 hdev->suspend_tasks)) {
4424 bt_dev_dbg(hdev, "Unpaused advertising");
4425 wake_up(&hdev->suspend_wait_q);
4426 }
4427
Arman Uguray24b4f382015-03-23 15:57:12 -07004428 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004429 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004430 */
4431 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004432 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004433 goto unlock;
4434
Florian Grandel7816b822015-06-18 03:16:45 +02004435 instance = hdev->cur_adv_instance;
4436 if (!instance) {
4437 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4438 struct adv_info, list);
4439 if (!adv_instance)
4440 goto unlock;
4441
4442 instance = adv_instance->instance;
4443 }
4444
Arman Uguray24b4f382015-03-23 15:57:12 -07004445 hci_req_init(&req, hdev);
4446
Johan Hedbergf2252572015-11-18 12:49:20 +02004447 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004448
Florian Grandel7816b822015-06-18 03:16:45 +02004449 if (!err)
4450 err = hci_req_run(&req, enable_advertising_instance);
4451
4452 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004453 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004454
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304455unlock:
4456 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004457}
4458
Marcel Holtmann21b51872013-10-10 09:47:53 -07004459static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4460 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004461{
4462 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004463 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004464 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004465 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004466 int err;
4467
4468 BT_DBG("request for %s", hdev->name);
4469
Johan Hedberge6fe7982013-10-02 15:45:22 +03004470 status = mgmt_le_support(hdev);
4471 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004472 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4473 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004474
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004475 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004476 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4477 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004478
Abhishek Pandit-Subedi4867bd02020-03-11 08:54:03 -07004479 if (hdev->advertising_paused)
4480 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4481 MGMT_STATUS_BUSY);
4482
Johan Hedberg4375f102013-09-25 13:26:10 +03004483 hci_dev_lock(hdev);
4484
4485 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004486
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004487 /* The following conditions are ones which mean that we should
4488 * not do any HCI communication but directly send a mgmt
4489 * response to user space (after toggling the flag if
4490 * necessary).
4491 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004492 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004493 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4494 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004495 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004496 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004497 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004498 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004499
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004500 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004501 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004502 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004503 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004504 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004505 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004506 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004507 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004508 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004509 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004510 }
4511
4512 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4513 if (err < 0)
4514 goto unlock;
4515
4516 if (changed)
4517 err = new_settings(hdev, sk);
4518
4519 goto unlock;
4520 }
4521
Johan Hedberg333ae952015-03-17 13:48:47 +02004522 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4523 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004524 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4525 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004526 goto unlock;
4527 }
4528
4529 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4530 if (!cmd) {
4531 err = -ENOMEM;
4532 goto unlock;
4533 }
4534
4535 hci_req_init(&req, hdev);
4536
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004537 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004538 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004539 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004540 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004541
Florian Grandel7816b822015-06-18 03:16:45 +02004542 cancel_adv_timeout(hdev);
4543
Arman Uguray24b4f382015-03-23 15:57:12 -07004544 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004545 /* Switch to instance "0" for the Set Advertising setting.
4546 * We cannot use update_[adv|scan_rsp]_data() here as the
4547 * HCI_ADVERTISING flag is not yet set.
4548 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004549 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304550
4551 if (ext_adv_capable(hdev)) {
4552 __hci_req_start_ext_adv(&req, 0x00);
4553 } else {
4554 __hci_req_update_adv_data(&req, 0x00);
4555 __hci_req_update_scan_rsp_data(&req, 0x00);
4556 __hci_req_enable_advertising(&req);
4557 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004558 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004559 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004560 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004561
4562 err = hci_req_run(&req, set_advertising_complete);
4563 if (err < 0)
4564 mgmt_pending_remove(cmd);
4565
4566unlock:
4567 hci_dev_unlock(hdev);
4568 return err;
4569}
4570
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004571static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4572 void *data, u16 len)
4573{
4574 struct mgmt_cp_set_static_address *cp = data;
4575 int err;
4576
4577 BT_DBG("%s", hdev->name);
4578
Marcel Holtmann62af4442013-10-02 22:10:32 -07004579 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004580 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4581 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004582
4583 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004584 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4585 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004586
4587 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4588 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004589 return mgmt_cmd_status(sk, hdev->id,
4590 MGMT_OP_SET_STATIC_ADDRESS,
4591 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004592
4593 /* Two most significant bits shall be set */
4594 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004595 return mgmt_cmd_status(sk, hdev->id,
4596 MGMT_OP_SET_STATIC_ADDRESS,
4597 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004598 }
4599
4600 hci_dev_lock(hdev);
4601
4602 bacpy(&hdev->static_addr, &cp->bdaddr);
4603
Marcel Holtmann93690c22015-03-06 10:11:21 -08004604 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4605 if (err < 0)
4606 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004607
Marcel Holtmann93690c22015-03-06 10:11:21 -08004608 err = new_settings(hdev, sk);
4609
4610unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004611 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004612 return err;
4613}
4614
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004615static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4616 void *data, u16 len)
4617{
4618 struct mgmt_cp_set_scan_params *cp = data;
4619 __u16 interval, window;
4620 int err;
4621
4622 BT_DBG("%s", hdev->name);
4623
4624 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004625 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4626 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004627
4628 interval = __le16_to_cpu(cp->interval);
4629
4630 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004631 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4632 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004633
4634 window = __le16_to_cpu(cp->window);
4635
4636 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004637 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4638 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004639
Marcel Holtmann899e1072013-10-14 09:55:32 -07004640 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004641 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4642 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004643
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004644 hci_dev_lock(hdev);
4645
4646 hdev->le_scan_interval = interval;
4647 hdev->le_scan_window = window;
4648
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004649 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4650 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004651
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004652 /* If background scan is running, restart it so new parameters are
4653 * loaded.
4654 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004655 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004656 hdev->discovery.state == DISCOVERY_STOPPED) {
4657 struct hci_request req;
4658
4659 hci_req_init(&req, hdev);
4660
4661 hci_req_add_le_scan_disable(&req);
4662 hci_req_add_le_passive_scan(&req);
4663
4664 hci_req_run(&req, NULL);
4665 }
4666
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004667 hci_dev_unlock(hdev);
4668
4669 return err;
4670}
4671
Marcel Holtmann1904a852015-01-11 13:50:44 -08004672static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4673 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004674{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004675 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004676
4677 BT_DBG("status 0x%02x", status);
4678
4679 hci_dev_lock(hdev);
4680
Johan Hedberg333ae952015-03-17 13:48:47 +02004681 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004682 if (!cmd)
4683 goto unlock;
4684
4685 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004686 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4687 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004688 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004689 struct mgmt_mode *cp = cmd->param;
4690
4691 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004692 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004693 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004694 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004695
Johan Hedberg33e38b32013-03-15 17:07:05 -05004696 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4697 new_settings(hdev, cmd->sk);
4698 }
4699
4700 mgmt_pending_remove(cmd);
4701
4702unlock:
4703 hci_dev_unlock(hdev);
4704}
4705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004706static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004707 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004708{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004709 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004710 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004711 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004712 int err;
4713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004714 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004715
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004716 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004717 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004718 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4719 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004720
Johan Hedberga7e80f22013-01-09 16:05:19 +02004721 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004722 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4723 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004724
Antti Julkuf6422ec2011-06-22 13:11:56 +03004725 hci_dev_lock(hdev);
4726
Johan Hedberg333ae952015-03-17 13:48:47 +02004727 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004728 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4729 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004730 goto unlock;
4731 }
4732
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004733 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004734 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4735 hdev);
4736 goto unlock;
4737 }
4738
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004739 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004740 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004741 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4742 hdev);
4743 new_settings(hdev, sk);
4744 goto unlock;
4745 }
4746
Johan Hedberg33e38b32013-03-15 17:07:05 -05004747 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4748 data, len);
4749 if (!cmd) {
4750 err = -ENOMEM;
4751 goto unlock;
4752 }
4753
4754 hci_req_init(&req, hdev);
4755
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004756 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004757
4758 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004759 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004760 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4761 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004762 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004763 }
4764
Johan Hedberg33e38b32013-03-15 17:07:05 -05004765unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004766 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004767
Antti Julkuf6422ec2011-06-22 13:11:56 +03004768 return err;
4769}
4770
Marcel Holtmann1904a852015-01-11 13:50:44 -08004771static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004772{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004773 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004774
4775 BT_DBG("status 0x%02x", status);
4776
4777 hci_dev_lock(hdev);
4778
Johan Hedberg333ae952015-03-17 13:48:47 +02004779 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004780 if (!cmd)
4781 goto unlock;
4782
4783 if (status) {
4784 u8 mgmt_err = mgmt_status(status);
4785
4786 /* We need to restore the flag if related HCI commands
4787 * failed.
4788 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004789 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004790
Johan Hedberga69e8372015-03-06 21:08:53 +02004791 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004792 } else {
4793 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4794 new_settings(hdev, cmd->sk);
4795 }
4796
4797 mgmt_pending_remove(cmd);
4798
4799unlock:
4800 hci_dev_unlock(hdev);
4801}
4802
4803static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4804{
4805 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004806 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004807 struct hci_request req;
4808 int err;
4809
4810 BT_DBG("request for %s", hdev->name);
4811
4812 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004813 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4814 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004815
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004816 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004817 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4818 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004819
4820 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004821 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4822 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004823
4824 hci_dev_lock(hdev);
4825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004826 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004827 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4828 goto unlock;
4829 }
4830
4831 if (!hdev_is_powered(hdev)) {
4832 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004833 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4834 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4835 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4836 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4837 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004838 }
4839
Marcel Holtmannce05d602015-03-13 02:11:03 -07004840 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004841
4842 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4843 if (err < 0)
4844 goto unlock;
4845
4846 err = new_settings(hdev, sk);
4847 goto unlock;
4848 }
4849
4850 /* Reject disabling when powered on */
4851 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004852 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4853 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004854 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004855 } else {
4856 /* When configuring a dual-mode controller to operate
4857 * with LE only and using a static address, then switching
4858 * BR/EDR back on is not allowed.
4859 *
4860 * Dual-mode controllers shall operate with the public
4861 * address as its identity address for BR/EDR and LE. So
4862 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004863 *
4864 * The same restrictions applies when secure connections
4865 * has been enabled. For BR/EDR this is a controller feature
4866 * while for LE it is a host stack feature. This means that
4867 * switching BR/EDR back on when secure connections has been
4868 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004869 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004870 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004871 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004872 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004873 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4874 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004875 goto unlock;
4876 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004877 }
4878
Johan Hedberg333ae952015-03-17 13:48:47 +02004879 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004880 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4881 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004882 goto unlock;
4883 }
4884
4885 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4886 if (!cmd) {
4887 err = -ENOMEM;
4888 goto unlock;
4889 }
4890
Johan Hedbergf2252572015-11-18 12:49:20 +02004891 /* We need to flip the bit already here so that
4892 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004893 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004894 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004895
4896 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004897
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004898 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004899 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004900
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004901 /* Since only the advertising data flags will change, there
4902 * is no need to update the scan response data.
4903 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004904 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004905
Johan Hedberg0663ca22013-10-02 13:43:14 +03004906 err = hci_req_run(&req, set_bredr_complete);
4907 if (err < 0)
4908 mgmt_pending_remove(cmd);
4909
4910unlock:
4911 hci_dev_unlock(hdev);
4912 return err;
4913}
4914
Johan Hedberga1443f52015-01-23 15:42:46 +02004915static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4916{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004917 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004918 struct mgmt_mode *cp;
4919
4920 BT_DBG("%s status %u", hdev->name, status);
4921
4922 hci_dev_lock(hdev);
4923
Johan Hedberg333ae952015-03-17 13:48:47 +02004924 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004925 if (!cmd)
4926 goto unlock;
4927
4928 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004929 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4930 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004931 goto remove;
4932 }
4933
4934 cp = cmd->param;
4935
4936 switch (cp->val) {
4937 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004938 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4939 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004940 break;
4941 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004942 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004943 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004944 break;
4945 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004946 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4947 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004948 break;
4949 }
4950
4951 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4952 new_settings(hdev, cmd->sk);
4953
4954remove:
4955 mgmt_pending_remove(cmd);
4956unlock:
4957 hci_dev_unlock(hdev);
4958}
4959
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004960static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4961 void *data, u16 len)
4962{
4963 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004964 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004965 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004966 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004967 int err;
4968
4969 BT_DBG("request for %s", hdev->name);
4970
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004971 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004972 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004973 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4974 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004975
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004976 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004977 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004978 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004979 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4980 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004981
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004982 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004983 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004984 MGMT_STATUS_INVALID_PARAMS);
4985
4986 hci_dev_lock(hdev);
4987
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004988 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004989 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004990 bool changed;
4991
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004992 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004993 changed = !hci_dev_test_and_set_flag(hdev,
4994 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004995 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004996 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004997 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004998 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004999 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005000 changed = hci_dev_test_and_clear_flag(hdev,
5001 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005002 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005003 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005004
5005 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5006 if (err < 0)
5007 goto failed;
5008
5009 if (changed)
5010 err = new_settings(hdev, sk);
5011
5012 goto failed;
5013 }
5014
Johan Hedberg333ae952015-03-17 13:48:47 +02005015 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005016 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5017 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005018 goto failed;
5019 }
5020
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005021 val = !!cp->val;
5022
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005023 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5024 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005025 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5026 goto failed;
5027 }
5028
5029 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5030 if (!cmd) {
5031 err = -ENOMEM;
5032 goto failed;
5033 }
5034
Johan Hedberga1443f52015-01-23 15:42:46 +02005035 hci_req_init(&req, hdev);
5036 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5037 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005038 if (err < 0) {
5039 mgmt_pending_remove(cmd);
5040 goto failed;
5041 }
5042
5043failed:
5044 hci_dev_unlock(hdev);
5045 return err;
5046}
5047
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005048static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5049 void *data, u16 len)
5050{
5051 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005052 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005053 int err;
5054
5055 BT_DBG("request for %s", hdev->name);
5056
Johan Hedbergb97109792014-06-24 14:00:28 +03005057 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005058 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5059 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005060
5061 hci_dev_lock(hdev);
5062
5063 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005064 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005065 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005066 changed = hci_dev_test_and_clear_flag(hdev,
5067 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005068
Johan Hedbergb97109792014-06-24 14:00:28 +03005069 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005070 use_changed = !hci_dev_test_and_set_flag(hdev,
5071 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005072 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005073 use_changed = hci_dev_test_and_clear_flag(hdev,
5074 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005075
5076 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005077 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005078 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5079 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5080 sizeof(mode), &mode);
5081 }
5082
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005083 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5084 if (err < 0)
5085 goto unlock;
5086
5087 if (changed)
5088 err = new_settings(hdev, sk);
5089
5090unlock:
5091 hci_dev_unlock(hdev);
5092 return err;
5093}
5094
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005095static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5096 u16 len)
5097{
5098 struct mgmt_cp_set_privacy *cp = cp_data;
5099 bool changed;
5100 int err;
5101
5102 BT_DBG("request for %s", hdev->name);
5103
5104 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005105 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5106 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005107
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005108 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005109 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5110 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005111
5112 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5114 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005115
5116 hci_dev_lock(hdev);
5117
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005118 /* If user space supports this command it is also expected to
5119 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5120 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005121 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005122
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005123 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005124 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005125 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005126 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305127 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005128 if (cp->privacy == 0x02)
5129 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5130 else
5131 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005132 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005133 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005134 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005135 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305136 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005137 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005138 }
5139
5140 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5141 if (err < 0)
5142 goto unlock;
5143
5144 if (changed)
5145 err = new_settings(hdev, sk);
5146
5147unlock:
5148 hci_dev_unlock(hdev);
5149 return err;
5150}
5151
Johan Hedberg41edf162014-02-18 10:19:35 +02005152static bool irk_is_valid(struct mgmt_irk_info *irk)
5153{
5154 switch (irk->addr.type) {
5155 case BDADDR_LE_PUBLIC:
5156 return true;
5157
5158 case BDADDR_LE_RANDOM:
5159 /* Two most significant bits shall be set */
5160 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5161 return false;
5162 return true;
5163 }
5164
5165 return false;
5166}
5167
5168static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5169 u16 len)
5170{
5171 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005172 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5173 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005174 u16 irk_count, expected_len;
5175 int i, err;
5176
5177 BT_DBG("request for %s", hdev->name);
5178
5179 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005180 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5181 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005182
5183 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005184 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005185 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5186 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005187 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5188 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005189 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005190
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005191 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005192 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005193 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5194 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005195 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5196 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005197 }
5198
5199 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5200
5201 for (i = 0; i < irk_count; i++) {
5202 struct mgmt_irk_info *key = &cp->irks[i];
5203
5204 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005205 return mgmt_cmd_status(sk, hdev->id,
5206 MGMT_OP_LOAD_IRKS,
5207 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005208 }
5209
5210 hci_dev_lock(hdev);
5211
5212 hci_smp_irks_clear(hdev);
5213
5214 for (i = 0; i < irk_count; i++) {
5215 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005216
Alain Michaud600a8742020-01-07 00:43:17 +00005217 if (hci_is_blocked_key(hdev,
5218 HCI_BLOCKED_KEY_TYPE_IRK,
5219 irk->val)) {
5220 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5221 &irk->addr.bdaddr);
5222 continue;
5223 }
5224
Johan Hedberg85813a72015-10-21 18:02:59 +03005225 hci_add_irk(hdev, &irk->addr.bdaddr,
5226 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005227 BDADDR_ANY);
5228 }
5229
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005230 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005231
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005232 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005233
5234 hci_dev_unlock(hdev);
5235
5236 return err;
5237}
5238
Johan Hedberg3f706b72013-01-20 14:27:16 +02005239static bool ltk_is_valid(struct mgmt_ltk_info *key)
5240{
5241 if (key->master != 0x00 && key->master != 0x01)
5242 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005243
5244 switch (key->addr.type) {
5245 case BDADDR_LE_PUBLIC:
5246 return true;
5247
5248 case BDADDR_LE_RANDOM:
5249 /* Two most significant bits shall be set */
5250 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5251 return false;
5252 return true;
5253 }
5254
5255 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005256}
5257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005258static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005259 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005260{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005261 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005262 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5263 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005264 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005265 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005266
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005267 BT_DBG("request for %s", hdev->name);
5268
5269 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005270 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5271 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005272
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005273 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005274 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005275 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5276 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005277 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5278 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005279 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005280
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005281 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005282 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005283 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5284 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005285 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5286 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005287 }
5288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005289 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005290
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005291 for (i = 0; i < key_count; i++) {
5292 struct mgmt_ltk_info *key = &cp->keys[i];
5293
Johan Hedberg3f706b72013-01-20 14:27:16 +02005294 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005295 return mgmt_cmd_status(sk, hdev->id,
5296 MGMT_OP_LOAD_LONG_TERM_KEYS,
5297 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005298 }
5299
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005300 hci_dev_lock(hdev);
5301
5302 hci_smp_ltks_clear(hdev);
5303
5304 for (i = 0; i < key_count; i++) {
5305 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005306 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005307
Alain Michaud600a8742020-01-07 00:43:17 +00005308 if (hci_is_blocked_key(hdev,
5309 HCI_BLOCKED_KEY_TYPE_LTK,
5310 key->val)) {
5311 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5312 &key->addr.bdaddr);
5313 continue;
5314 }
5315
Johan Hedberg61b43352014-05-29 19:36:53 +03005316 switch (key->type) {
5317 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005318 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005319 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005320 break;
5321 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005322 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005323 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005324 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005325 case MGMT_LTK_P256_UNAUTH:
5326 authenticated = 0x00;
5327 type = SMP_LTK_P256;
5328 break;
5329 case MGMT_LTK_P256_AUTH:
5330 authenticated = 0x01;
5331 type = SMP_LTK_P256;
5332 break;
5333 case MGMT_LTK_P256_DEBUG:
5334 authenticated = 0x00;
5335 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005336 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005337 default:
5338 continue;
5339 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005340
Johan Hedberg85813a72015-10-21 18:02:59 +03005341 hci_add_ltk(hdev, &key->addr.bdaddr,
5342 le_addr_type(key->addr.type), type, authenticated,
5343 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005344 }
5345
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005346 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005347 NULL, 0);
5348
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005349 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005350
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005351 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005352}
5353
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005354static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005355{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005356 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005357 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005358 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005359
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005360 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005361
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005362 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005363 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005364 rp.tx_power = conn->tx_power;
5365 rp.max_tx_power = conn->max_tx_power;
5366 } else {
5367 rp.rssi = HCI_RSSI_INVALID;
5368 rp.tx_power = HCI_TX_POWER_INVALID;
5369 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005370 }
5371
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005372 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5373 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005374
5375 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005376 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005377
5378 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005379}
5380
Marcel Holtmann1904a852015-01-11 13:50:44 -08005381static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5382 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005383{
5384 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005385 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005386 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005387 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005388 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005389
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005390 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005391
5392 hci_dev_lock(hdev);
5393
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005394 /* Commands sent in request are either Read RSSI or Read Transmit Power
5395 * Level so we check which one was last sent to retrieve connection
5396 * handle. Both commands have handle as first parameter so it's safe to
5397 * cast data on the same command struct.
5398 *
5399 * First command sent is always Read RSSI and we fail only if it fails.
5400 * In other case we simply override error to indicate success as we
5401 * already remembered if TX power value is actually valid.
5402 */
5403 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5404 if (!cp) {
5405 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005406 status = MGMT_STATUS_SUCCESS;
5407 } else {
5408 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005409 }
5410
5411 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005412 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005413 goto unlock;
5414 }
5415
5416 handle = __le16_to_cpu(cp->handle);
5417 conn = hci_conn_hash_lookup_handle(hdev, handle);
5418 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005419 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5420 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005421 goto unlock;
5422 }
5423
Johan Hedberg333ae952015-03-17 13:48:47 +02005424 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005425 if (!cmd)
5426 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005427
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005428 cmd->cmd_complete(cmd, status);
5429 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005430
5431unlock:
5432 hci_dev_unlock(hdev);
5433}
5434
5435static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5436 u16 len)
5437{
5438 struct mgmt_cp_get_conn_info *cp = data;
5439 struct mgmt_rp_get_conn_info rp;
5440 struct hci_conn *conn;
5441 unsigned long conn_info_age;
5442 int err = 0;
5443
5444 BT_DBG("%s", hdev->name);
5445
5446 memset(&rp, 0, sizeof(rp));
5447 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5448 rp.addr.type = cp->addr.type;
5449
5450 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005451 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5452 MGMT_STATUS_INVALID_PARAMS,
5453 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005454
5455 hci_dev_lock(hdev);
5456
5457 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005458 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5459 MGMT_STATUS_NOT_POWERED, &rp,
5460 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005461 goto unlock;
5462 }
5463
5464 if (cp->addr.type == BDADDR_BREDR)
5465 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5466 &cp->addr.bdaddr);
5467 else
5468 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5469
5470 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005471 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5472 MGMT_STATUS_NOT_CONNECTED, &rp,
5473 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005474 goto unlock;
5475 }
5476
Johan Hedberg333ae952015-03-17 13:48:47 +02005477 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005478 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5479 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005480 goto unlock;
5481 }
5482
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005483 /* To avoid client trying to guess when to poll again for information we
5484 * calculate conn info age as random value between min/max set in hdev.
5485 */
5486 conn_info_age = hdev->conn_info_min_age +
5487 prandom_u32_max(hdev->conn_info_max_age -
5488 hdev->conn_info_min_age);
5489
5490 /* Query controller to refresh cached values if they are too old or were
5491 * never read.
5492 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005493 if (time_after(jiffies, conn->conn_info_timestamp +
5494 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005495 !conn->conn_info_timestamp) {
5496 struct hci_request req;
5497 struct hci_cp_read_tx_power req_txp_cp;
5498 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005499 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005500
5501 hci_req_init(&req, hdev);
5502 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5503 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5504 &req_rssi_cp);
5505
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005506 /* For LE links TX power does not change thus we don't need to
5507 * query for it once value is known.
5508 */
5509 if (!bdaddr_type_is_le(cp->addr.type) ||
5510 conn->tx_power == HCI_TX_POWER_INVALID) {
5511 req_txp_cp.handle = cpu_to_le16(conn->handle);
5512 req_txp_cp.type = 0x00;
5513 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5514 sizeof(req_txp_cp), &req_txp_cp);
5515 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005516
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005517 /* Max TX power needs to be read only once per connection */
5518 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5519 req_txp_cp.handle = cpu_to_le16(conn->handle);
5520 req_txp_cp.type = 0x01;
5521 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5522 sizeof(req_txp_cp), &req_txp_cp);
5523 }
5524
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005525 err = hci_req_run(&req, conn_info_refresh_complete);
5526 if (err < 0)
5527 goto unlock;
5528
5529 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5530 data, len);
5531 if (!cmd) {
5532 err = -ENOMEM;
5533 goto unlock;
5534 }
5535
5536 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005537 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005538 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005539
5540 conn->conn_info_timestamp = jiffies;
5541 } else {
5542 /* Cache is valid, just reply with values cached in hci_conn */
5543 rp.rssi = conn->rssi;
5544 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005545 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005546
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005547 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5548 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005549 }
5550
5551unlock:
5552 hci_dev_unlock(hdev);
5553 return err;
5554}
5555
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005556static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005557{
5558 struct hci_conn *conn = cmd->user_data;
5559 struct mgmt_rp_get_clock_info rp;
5560 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005561 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005562
5563 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005564 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005565
5566 if (status)
5567 goto complete;
5568
5569 hdev = hci_dev_get(cmd->index);
5570 if (hdev) {
5571 rp.local_clock = cpu_to_le32(hdev->clock);
5572 hci_dev_put(hdev);
5573 }
5574
5575 if (conn) {
5576 rp.piconet_clock = cpu_to_le32(conn->clock);
5577 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5578 }
5579
5580complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005581 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5582 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005583
5584 if (conn) {
5585 hci_conn_drop(conn);
5586 hci_conn_put(conn);
5587 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005588
5589 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005590}
5591
Marcel Holtmann1904a852015-01-11 13:50:44 -08005592static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005593{
Johan Hedberg95868422014-06-28 17:54:07 +03005594 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005595 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005596 struct hci_conn *conn;
5597
5598 BT_DBG("%s status %u", hdev->name, status);
5599
5600 hci_dev_lock(hdev);
5601
5602 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5603 if (!hci_cp)
5604 goto unlock;
5605
5606 if (hci_cp->which) {
5607 u16 handle = __le16_to_cpu(hci_cp->handle);
5608 conn = hci_conn_hash_lookup_handle(hdev, handle);
5609 } else {
5610 conn = NULL;
5611 }
5612
Johan Hedberg333ae952015-03-17 13:48:47 +02005613 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005614 if (!cmd)
5615 goto unlock;
5616
Johan Hedberg69487372014-12-05 13:36:07 +02005617 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005618 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005619
5620unlock:
5621 hci_dev_unlock(hdev);
5622}
5623
5624static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5625 u16 len)
5626{
5627 struct mgmt_cp_get_clock_info *cp = data;
5628 struct mgmt_rp_get_clock_info rp;
5629 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005630 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005631 struct hci_request req;
5632 struct hci_conn *conn;
5633 int err;
5634
5635 BT_DBG("%s", hdev->name);
5636
5637 memset(&rp, 0, sizeof(rp));
5638 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5639 rp.addr.type = cp->addr.type;
5640
5641 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005642 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5643 MGMT_STATUS_INVALID_PARAMS,
5644 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005645
5646 hci_dev_lock(hdev);
5647
5648 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005649 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5650 MGMT_STATUS_NOT_POWERED, &rp,
5651 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005652 goto unlock;
5653 }
5654
5655 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5656 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5657 &cp->addr.bdaddr);
5658 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005659 err = mgmt_cmd_complete(sk, hdev->id,
5660 MGMT_OP_GET_CLOCK_INFO,
5661 MGMT_STATUS_NOT_CONNECTED,
5662 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005663 goto unlock;
5664 }
5665 } else {
5666 conn = NULL;
5667 }
5668
5669 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5670 if (!cmd) {
5671 err = -ENOMEM;
5672 goto unlock;
5673 }
5674
Johan Hedberg69487372014-12-05 13:36:07 +02005675 cmd->cmd_complete = clock_info_cmd_complete;
5676
Johan Hedberg95868422014-06-28 17:54:07 +03005677 hci_req_init(&req, hdev);
5678
5679 memset(&hci_cp, 0, sizeof(hci_cp));
5680 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5681
5682 if (conn) {
5683 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005684 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005685
5686 hci_cp.handle = cpu_to_le16(conn->handle);
5687 hci_cp.which = 0x01; /* Piconet clock */
5688 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5689 }
5690
5691 err = hci_req_run(&req, get_clock_info_complete);
5692 if (err < 0)
5693 mgmt_pending_remove(cmd);
5694
5695unlock:
5696 hci_dev_unlock(hdev);
5697 return err;
5698}
5699
Johan Hedberg5a154e62014-12-19 22:26:02 +02005700static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5701{
5702 struct hci_conn *conn;
5703
5704 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5705 if (!conn)
5706 return false;
5707
5708 if (conn->dst_type != type)
5709 return false;
5710
5711 if (conn->state != BT_CONNECTED)
5712 return false;
5713
5714 return true;
5715}
5716
5717/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005718static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005719 u8 addr_type, u8 auto_connect)
5720{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005721 struct hci_conn_params *params;
5722
5723 params = hci_conn_params_add(hdev, addr, addr_type);
5724 if (!params)
5725 return -EIO;
5726
5727 if (params->auto_connect == auto_connect)
5728 return 0;
5729
5730 list_del_init(&params->action);
5731
5732 switch (auto_connect) {
5733 case HCI_AUTO_CONN_DISABLED:
5734 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005735 /* If auto connect is being disabled when we're trying to
5736 * connect to device, keep connecting.
5737 */
5738 if (params->explicit_connect)
5739 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005740 break;
5741 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005742 if (params->explicit_connect)
5743 list_add(&params->action, &hdev->pend_le_conns);
5744 else
5745 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005746 break;
5747 case HCI_AUTO_CONN_DIRECT:
5748 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005749 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005750 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005751 break;
5752 }
5753
5754 params->auto_connect = auto_connect;
5755
5756 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5757 auto_connect);
5758
5759 return 0;
5760}
5761
Marcel Holtmann8afef092014-06-29 22:28:34 +02005762static void device_added(struct sock *sk, struct hci_dev *hdev,
5763 bdaddr_t *bdaddr, u8 type, u8 action)
5764{
5765 struct mgmt_ev_device_added ev;
5766
5767 bacpy(&ev.addr.bdaddr, bdaddr);
5768 ev.addr.type = type;
5769 ev.action = action;
5770
5771 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5772}
5773
Marcel Holtmann2faade52014-06-29 19:44:03 +02005774static int add_device(struct sock *sk, struct hci_dev *hdev,
5775 void *data, u16 len)
5776{
5777 struct mgmt_cp_add_device *cp = data;
5778 u8 auto_conn, addr_type;
5779 int err;
5780
5781 BT_DBG("%s", hdev->name);
5782
Johan Hedberg66593582014-07-09 12:59:14 +03005783 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005784 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005785 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5786 MGMT_STATUS_INVALID_PARAMS,
5787 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005788
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005789 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005790 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5791 MGMT_STATUS_INVALID_PARAMS,
5792 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005793
5794 hci_dev_lock(hdev);
5795
Johan Hedberg66593582014-07-09 12:59:14 +03005796 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005797 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005798 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005799 err = mgmt_cmd_complete(sk, hdev->id,
5800 MGMT_OP_ADD_DEVICE,
5801 MGMT_STATUS_INVALID_PARAMS,
5802 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005803 goto unlock;
5804 }
5805
5806 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5807 cp->addr.type);
5808 if (err)
5809 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005810
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005811 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005812
Johan Hedberg66593582014-07-09 12:59:14 +03005813 goto added;
5814 }
5815
Johan Hedberg85813a72015-10-21 18:02:59 +03005816 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005817
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005818 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005819 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005820 else if (cp->action == 0x01)
5821 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005822 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005823 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005824
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005825 /* Kernel internally uses conn_params with resolvable private
5826 * address, but Add Device allows only identity addresses.
5827 * Make sure it is enforced before calling
5828 * hci_conn_params_lookup.
5829 */
5830 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005831 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5832 MGMT_STATUS_INVALID_PARAMS,
5833 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005834 goto unlock;
5835 }
5836
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005837 /* If the connection parameters don't exist for this device,
5838 * they will be created and configured with defaults.
5839 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005840 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005841 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005842 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5843 MGMT_STATUS_FAILED, &cp->addr,
5844 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005845 goto unlock;
5846 }
5847
Johan Hedberg51d7a942015-11-11 08:11:18 +02005848 hci_update_background_scan(hdev);
5849
Johan Hedberg66593582014-07-09 12:59:14 +03005850added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005851 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5852
Johan Hedberg51d7a942015-11-11 08:11:18 +02005853 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5854 MGMT_STATUS_SUCCESS, &cp->addr,
5855 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005856
5857unlock:
5858 hci_dev_unlock(hdev);
5859 return err;
5860}
5861
Marcel Holtmann8afef092014-06-29 22:28:34 +02005862static void device_removed(struct sock *sk, struct hci_dev *hdev,
5863 bdaddr_t *bdaddr, u8 type)
5864{
5865 struct mgmt_ev_device_removed ev;
5866
5867 bacpy(&ev.addr.bdaddr, bdaddr);
5868 ev.addr.type = type;
5869
5870 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5871}
5872
Marcel Holtmann2faade52014-06-29 19:44:03 +02005873static int remove_device(struct sock *sk, struct hci_dev *hdev,
5874 void *data, u16 len)
5875{
5876 struct mgmt_cp_remove_device *cp = data;
5877 int err;
5878
5879 BT_DBG("%s", hdev->name);
5880
5881 hci_dev_lock(hdev);
5882
5883 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005884 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005885 u8 addr_type;
5886
Johan Hedberg66593582014-07-09 12:59:14 +03005887 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005888 err = mgmt_cmd_complete(sk, hdev->id,
5889 MGMT_OP_REMOVE_DEVICE,
5890 MGMT_STATUS_INVALID_PARAMS,
5891 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005892 goto unlock;
5893 }
5894
Johan Hedberg66593582014-07-09 12:59:14 +03005895 if (cp->addr.type == BDADDR_BREDR) {
5896 err = hci_bdaddr_list_del(&hdev->whitelist,
5897 &cp->addr.bdaddr,
5898 cp->addr.type);
5899 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005900 err = mgmt_cmd_complete(sk, hdev->id,
5901 MGMT_OP_REMOVE_DEVICE,
5902 MGMT_STATUS_INVALID_PARAMS,
5903 &cp->addr,
5904 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005905 goto unlock;
5906 }
5907
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005908 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005909
Johan Hedberg66593582014-07-09 12:59:14 +03005910 device_removed(sk, hdev, &cp->addr.bdaddr,
5911 cp->addr.type);
5912 goto complete;
5913 }
5914
Johan Hedberg85813a72015-10-21 18:02:59 +03005915 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005916
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005917 /* Kernel internally uses conn_params with resolvable private
5918 * address, but Remove Device allows only identity addresses.
5919 * Make sure it is enforced before calling
5920 * hci_conn_params_lookup.
5921 */
5922 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005923 err = mgmt_cmd_complete(sk, hdev->id,
5924 MGMT_OP_REMOVE_DEVICE,
5925 MGMT_STATUS_INVALID_PARAMS,
5926 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005927 goto unlock;
5928 }
5929
Johan Hedbergc71593d2014-07-02 17:37:28 +03005930 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5931 addr_type);
5932 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005933 err = mgmt_cmd_complete(sk, hdev->id,
5934 MGMT_OP_REMOVE_DEVICE,
5935 MGMT_STATUS_INVALID_PARAMS,
5936 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005937 goto unlock;
5938 }
5939
Johan Hedberg679d2b62015-10-16 10:07:52 +03005940 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5941 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005942 err = mgmt_cmd_complete(sk, hdev->id,
5943 MGMT_OP_REMOVE_DEVICE,
5944 MGMT_STATUS_INVALID_PARAMS,
5945 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005946 goto unlock;
5947 }
5948
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005949 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005950 list_del(&params->list);
5951 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005952 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005953
5954 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005955 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005956 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005957 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005958
Marcel Holtmann2faade52014-06-29 19:44:03 +02005959 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005960 err = mgmt_cmd_complete(sk, hdev->id,
5961 MGMT_OP_REMOVE_DEVICE,
5962 MGMT_STATUS_INVALID_PARAMS,
5963 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005964 goto unlock;
5965 }
5966
Johan Hedberg66593582014-07-09 12:59:14 +03005967 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5968 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5969 list_del(&b->list);
5970 kfree(b);
5971 }
5972
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005973 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005974
Johan Hedberg19de0822014-07-06 13:06:51 +03005975 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5976 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5977 continue;
5978 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005979 if (p->explicit_connect) {
5980 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5981 continue;
5982 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005983 list_del(&p->action);
5984 list_del(&p->list);
5985 kfree(p);
5986 }
5987
5988 BT_DBG("All LE connection parameters were removed");
5989
Johan Hedberg51d7a942015-11-11 08:11:18 +02005990 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005991 }
5992
Johan Hedberg66593582014-07-09 12:59:14 +03005993complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005994 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5995 MGMT_STATUS_SUCCESS, &cp->addr,
5996 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005997unlock:
5998 hci_dev_unlock(hdev);
5999 return err;
6000}
6001
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006002static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6003 u16 len)
6004{
6005 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006006 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6007 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006008 u16 param_count, expected_len;
6009 int i;
6010
6011 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006012 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6013 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006014
6015 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006016 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006017 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
6018 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006019 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6020 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006021 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006022
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05006023 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006024 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006025 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
6026 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006027 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6028 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006029 }
6030
6031 BT_DBG("%s param_count %u", hdev->name, param_count);
6032
6033 hci_dev_lock(hdev);
6034
6035 hci_conn_params_clear_disabled(hdev);
6036
6037 for (i = 0; i < param_count; i++) {
6038 struct mgmt_conn_param *param = &cp->params[i];
6039 struct hci_conn_params *hci_param;
6040 u16 min, max, latency, timeout;
6041 u8 addr_type;
6042
6043 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6044 param->addr.type);
6045
6046 if (param->addr.type == BDADDR_LE_PUBLIC) {
6047 addr_type = ADDR_LE_DEV_PUBLIC;
6048 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6049 addr_type = ADDR_LE_DEV_RANDOM;
6050 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006051 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006052 continue;
6053 }
6054
6055 min = le16_to_cpu(param->min_interval);
6056 max = le16_to_cpu(param->max_interval);
6057 latency = le16_to_cpu(param->latency);
6058 timeout = le16_to_cpu(param->timeout);
6059
6060 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6061 min, max, latency, timeout);
6062
6063 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006064 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006065 continue;
6066 }
6067
6068 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6069 addr_type);
6070 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006071 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006072 continue;
6073 }
6074
6075 hci_param->conn_min_interval = min;
6076 hci_param->conn_max_interval = max;
6077 hci_param->conn_latency = latency;
6078 hci_param->supervision_timeout = timeout;
6079 }
6080
6081 hci_dev_unlock(hdev);
6082
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006083 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6084 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006085}
6086
Marcel Holtmanndbece372014-07-04 18:11:55 +02006087static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6088 void *data, u16 len)
6089{
6090 struct mgmt_cp_set_external_config *cp = data;
6091 bool changed;
6092 int err;
6093
6094 BT_DBG("%s", hdev->name);
6095
6096 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006097 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6098 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006099
6100 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006101 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6102 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006103
6104 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006105 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6106 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006107
6108 hci_dev_lock(hdev);
6109
6110 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006111 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006112 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006113 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006114
6115 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6116 if (err < 0)
6117 goto unlock;
6118
6119 if (!changed)
6120 goto unlock;
6121
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006122 err = new_options(hdev, sk);
6123
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006124 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006125 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006126
Marcel Holtmann516018a2015-03-13 02:11:04 -07006127 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006128 hci_dev_set_flag(hdev, HCI_CONFIG);
6129 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006130
6131 queue_work(hdev->req_workqueue, &hdev->power_on);
6132 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006133 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006134 mgmt_index_added(hdev);
6135 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006136 }
6137
6138unlock:
6139 hci_dev_unlock(hdev);
6140 return err;
6141}
6142
Marcel Holtmann9713c172014-07-06 12:11:15 +02006143static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6144 void *data, u16 len)
6145{
6146 struct mgmt_cp_set_public_address *cp = data;
6147 bool changed;
6148 int err;
6149
6150 BT_DBG("%s", hdev->name);
6151
6152 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6154 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006155
6156 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006157 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6158 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006159
6160 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006161 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6162 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006163
6164 hci_dev_lock(hdev);
6165
6166 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6167 bacpy(&hdev->public_addr, &cp->bdaddr);
6168
6169 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6170 if (err < 0)
6171 goto unlock;
6172
6173 if (!changed)
6174 goto unlock;
6175
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006176 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006177 err = new_options(hdev, sk);
6178
6179 if (is_configured(hdev)) {
6180 mgmt_index_removed(hdev);
6181
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006182 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006183
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006184 hci_dev_set_flag(hdev, HCI_CONFIG);
6185 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006186
6187 queue_work(hdev->req_workqueue, &hdev->power_on);
6188 }
6189
6190unlock:
6191 hci_dev_unlock(hdev);
6192 return err;
6193}
6194
Johan Hedberg40f66c02015-04-07 21:52:22 +03006195static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6196 u16 opcode, struct sk_buff *skb)
6197{
6198 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6199 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6200 u8 *h192, *r192, *h256, *r256;
6201 struct mgmt_pending_cmd *cmd;
6202 u16 eir_len;
6203 int err;
6204
6205 BT_DBG("%s status %u", hdev->name, status);
6206
6207 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6208 if (!cmd)
6209 return;
6210
6211 mgmt_cp = cmd->param;
6212
6213 if (status) {
6214 status = mgmt_status(status);
6215 eir_len = 0;
6216
6217 h192 = NULL;
6218 r192 = NULL;
6219 h256 = NULL;
6220 r256 = NULL;
6221 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6222 struct hci_rp_read_local_oob_data *rp;
6223
6224 if (skb->len != sizeof(*rp)) {
6225 status = MGMT_STATUS_FAILED;
6226 eir_len = 0;
6227 } else {
6228 status = MGMT_STATUS_SUCCESS;
6229 rp = (void *)skb->data;
6230
6231 eir_len = 5 + 18 + 18;
6232 h192 = rp->hash;
6233 r192 = rp->rand;
6234 h256 = NULL;
6235 r256 = NULL;
6236 }
6237 } else {
6238 struct hci_rp_read_local_oob_ext_data *rp;
6239
6240 if (skb->len != sizeof(*rp)) {
6241 status = MGMT_STATUS_FAILED;
6242 eir_len = 0;
6243 } else {
6244 status = MGMT_STATUS_SUCCESS;
6245 rp = (void *)skb->data;
6246
6247 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6248 eir_len = 5 + 18 + 18;
6249 h192 = NULL;
6250 r192 = NULL;
6251 } else {
6252 eir_len = 5 + 18 + 18 + 18 + 18;
6253 h192 = rp->hash192;
6254 r192 = rp->rand192;
6255 }
6256
6257 h256 = rp->hash256;
6258 r256 = rp->rand256;
6259 }
6260 }
6261
6262 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6263 if (!mgmt_rp)
6264 goto done;
6265
6266 if (status)
6267 goto send_rsp;
6268
6269 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6270 hdev->dev_class, 3);
6271
6272 if (h192 && r192) {
6273 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6274 EIR_SSP_HASH_C192, h192, 16);
6275 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6276 EIR_SSP_RAND_R192, r192, 16);
6277 }
6278
6279 if (h256 && r256) {
6280 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6281 EIR_SSP_HASH_C256, h256, 16);
6282 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6283 EIR_SSP_RAND_R256, r256, 16);
6284 }
6285
6286send_rsp:
6287 mgmt_rp->type = mgmt_cp->type;
6288 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6289
6290 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6291 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6292 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6293 if (err < 0 || status)
6294 goto done;
6295
6296 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6297
6298 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6299 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6300 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6301done:
6302 kfree(mgmt_rp);
6303 mgmt_pending_remove(cmd);
6304}
6305
6306static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6307 struct mgmt_cp_read_local_oob_ext_data *cp)
6308{
6309 struct mgmt_pending_cmd *cmd;
6310 struct hci_request req;
6311 int err;
6312
6313 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6314 cp, sizeof(*cp));
6315 if (!cmd)
6316 return -ENOMEM;
6317
6318 hci_req_init(&req, hdev);
6319
6320 if (bredr_sc_enabled(hdev))
6321 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6322 else
6323 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6324
6325 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6326 if (err < 0) {
6327 mgmt_pending_remove(cmd);
6328 return err;
6329 }
6330
6331 return 0;
6332}
6333
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006334static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6335 void *data, u16 data_len)
6336{
6337 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6338 struct mgmt_rp_read_local_oob_ext_data *rp;
6339 size_t rp_len;
6340 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006341 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006342 int err;
6343
6344 BT_DBG("%s", hdev->name);
6345
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006346 if (hdev_is_powered(hdev)) {
6347 switch (cp->type) {
6348 case BIT(BDADDR_BREDR):
6349 status = mgmt_bredr_support(hdev);
6350 if (status)
6351 eir_len = 0;
6352 else
6353 eir_len = 5;
6354 break;
6355 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6356 status = mgmt_le_support(hdev);
6357 if (status)
6358 eir_len = 0;
6359 else
6360 eir_len = 9 + 3 + 18 + 18 + 3;
6361 break;
6362 default:
6363 status = MGMT_STATUS_INVALID_PARAMS;
6364 eir_len = 0;
6365 break;
6366 }
6367 } else {
6368 status = MGMT_STATUS_NOT_POWERED;
6369 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006370 }
6371
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006372 rp_len = sizeof(*rp) + eir_len;
6373 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006374 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006375 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006376
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006377 if (status)
6378 goto complete;
6379
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006380 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006381
6382 eir_len = 0;
6383 switch (cp->type) {
6384 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006385 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6386 err = read_local_ssp_oob_req(hdev, sk, cp);
6387 hci_dev_unlock(hdev);
6388 if (!err)
6389 goto done;
6390
6391 status = MGMT_STATUS_FAILED;
6392 goto complete;
6393 } else {
6394 eir_len = eir_append_data(rp->eir, eir_len,
6395 EIR_CLASS_OF_DEV,
6396 hdev->dev_class, 3);
6397 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006398 break;
6399 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006400 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6401 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006402 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006403 status = MGMT_STATUS_FAILED;
6404 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006405 }
6406
Marcel Holtmanne2135682015-04-02 12:00:58 -07006407 /* This should return the active RPA, but since the RPA
6408 * is only programmed on demand, it is really hard to fill
6409 * this in at the moment. For now disallow retrieving
6410 * local out-of-band data when privacy is in use.
6411 *
6412 * Returning the identity address will not help here since
6413 * pairing happens before the identity resolving key is
6414 * known and thus the connection establishment happens
6415 * based on the RPA and not the identity address.
6416 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006417 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006418 hci_dev_unlock(hdev);
6419 status = MGMT_STATUS_REJECTED;
6420 goto complete;
6421 }
6422
6423 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6424 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6425 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6426 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006427 memcpy(addr, &hdev->static_addr, 6);
6428 addr[6] = 0x01;
6429 } else {
6430 memcpy(addr, &hdev->bdaddr, 6);
6431 addr[6] = 0x00;
6432 }
6433
6434 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6435 addr, sizeof(addr));
6436
6437 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6438 role = 0x02;
6439 else
6440 role = 0x01;
6441
6442 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6443 &role, sizeof(role));
6444
Marcel Holtmann5082a592015-03-16 12:39:00 -07006445 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6446 eir_len = eir_append_data(rp->eir, eir_len,
6447 EIR_LE_SC_CONFIRM,
6448 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006449
Marcel Holtmann5082a592015-03-16 12:39:00 -07006450 eir_len = eir_append_data(rp->eir, eir_len,
6451 EIR_LE_SC_RANDOM,
6452 rand, sizeof(rand));
6453 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006454
Johan Hedbergf2252572015-11-18 12:49:20 +02006455 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006456
6457 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6458 flags |= LE_AD_NO_BREDR;
6459
6460 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6461 &flags, sizeof(flags));
6462 break;
6463 }
6464
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006465 hci_dev_unlock(hdev);
6466
Marcel Holtmann72000df2015-03-16 16:11:21 -07006467 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6468
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006469 status = MGMT_STATUS_SUCCESS;
6470
6471complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006472 rp->type = cp->type;
6473 rp->eir_len = cpu_to_le16(eir_len);
6474
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006475 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006476 status, rp, sizeof(*rp) + eir_len);
6477 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006478 goto done;
6479
6480 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6481 rp, sizeof(*rp) + eir_len,
6482 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006483
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006484done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006485 kfree(rp);
6486
6487 return err;
6488}
6489
Arman Uguray089fa8c2015-03-25 18:53:45 -07006490static u32 get_supported_adv_flags(struct hci_dev *hdev)
6491{
6492 u32 flags = 0;
6493
6494 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6495 flags |= MGMT_ADV_FLAG_DISCOV;
6496 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6497 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006498 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006499 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006500
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306501 /* In extended adv TX_POWER returned from Set Adv Param
6502 * will be always valid.
6503 */
6504 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6505 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006506 flags |= MGMT_ADV_FLAG_TX_POWER;
6507
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306508 if (ext_adv_capable(hdev)) {
6509 flags |= MGMT_ADV_FLAG_SEC_1M;
6510
6511 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6512 flags |= MGMT_ADV_FLAG_SEC_2M;
6513
6514 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6515 flags |= MGMT_ADV_FLAG_SEC_CODED;
6516 }
6517
Arman Uguray089fa8c2015-03-25 18:53:45 -07006518 return flags;
6519}
6520
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006521static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6522 void *data, u16 data_len)
6523{
6524 struct mgmt_rp_read_adv_features *rp;
6525 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006526 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006527 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006528 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006529 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006530
6531 BT_DBG("%s", hdev->name);
6532
Arman Uguray089fa8c2015-03-25 18:53:45 -07006533 if (!lmp_le_capable(hdev))
6534 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6535 MGMT_STATUS_REJECTED);
6536
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006537 hci_dev_lock(hdev);
6538
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006539 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006540 rp = kmalloc(rp_len, GFP_ATOMIC);
6541 if (!rp) {
6542 hci_dev_unlock(hdev);
6543 return -ENOMEM;
6544 }
6545
Arman Uguray089fa8c2015-03-25 18:53:45 -07006546 supported_flags = get_supported_adv_flags(hdev);
6547
6548 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006549 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6550 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006551 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006552 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006553
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006554 instance = rp->instance;
6555 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6556 *instance = adv_instance->instance;
6557 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006558 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006559
6560 hci_dev_unlock(hdev);
6561
6562 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6563 MGMT_STATUS_SUCCESS, rp, rp_len);
6564
6565 kfree(rp);
6566
6567 return err;
6568}
6569
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006570static u8 calculate_name_len(struct hci_dev *hdev)
6571{
6572 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6573
6574 return append_local_name(hdev, buf, 0);
6575}
6576
6577static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6578 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006579{
Arman Uguray4117ed72015-03-23 15:57:14 -07006580 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006581
Marcel Holtmann31a32482015-11-19 16:16:42 +01006582 if (is_adv_data) {
6583 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6584 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006585 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006586 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006587
Szymon Janc2bb368702016-09-18 12:50:05 +02006588 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006589 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006590 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006591 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006592 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006593
Szymon Janc2bb368702016-09-18 12:50:05 +02006594 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006595 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006596 }
6597
Szymon Janc2bb368702016-09-18 12:50:05 +02006598 return max_len;
6599}
6600
6601static bool flags_managed(u32 adv_flags)
6602{
6603 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6604 MGMT_ADV_FLAG_LIMITED_DISCOV |
6605 MGMT_ADV_FLAG_MANAGED_FLAGS);
6606}
6607
6608static bool tx_power_managed(u32 adv_flags)
6609{
6610 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6611}
6612
6613static bool name_managed(u32 adv_flags)
6614{
6615 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6616}
6617
6618static bool appearance_managed(u32 adv_flags)
6619{
6620 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6621}
6622
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006623static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6624 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006625{
6626 int i, cur_len;
6627 u8 max_len;
6628
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006629 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006630
Arman Uguray4117ed72015-03-23 15:57:14 -07006631 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006632 return false;
6633
Arman Uguray4117ed72015-03-23 15:57:14 -07006634 /* Make sure that the data is correctly formatted. */
6635 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6636 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006637
Szymon Janc9c9db782016-09-18 12:50:06 +02006638 if (data[i + 1] == EIR_FLAGS &&
6639 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006640 return false;
6641
Szymon Janc2bb368702016-09-18 12:50:05 +02006642 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6643 return false;
6644
6645 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6646 return false;
6647
6648 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6649 return false;
6650
6651 if (data[i + 1] == EIR_APPEARANCE &&
6652 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006653 return false;
6654
Arman Uguray24b4f382015-03-23 15:57:12 -07006655 /* If the current field length would exceed the total data
6656 * length, then it's invalid.
6657 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006658 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006659 return false;
6660 }
6661
6662 return true;
6663}
6664
Arman Uguray24b4f382015-03-23 15:57:12 -07006665static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6666 u16 opcode)
6667{
6668 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006669 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006670 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006671 struct adv_info *adv_instance, *n;
6672 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006673
6674 BT_DBG("status %d", status);
6675
6676 hci_dev_lock(hdev);
6677
6678 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6679
Florian Grandelfffd38b2015-06-18 03:16:47 +02006680 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6681 if (!adv_instance->pending)
6682 continue;
6683
6684 if (!status) {
6685 adv_instance->pending = false;
6686 continue;
6687 }
6688
6689 instance = adv_instance->instance;
6690
6691 if (hdev->cur_adv_instance == instance)
6692 cancel_adv_timeout(hdev);
6693
6694 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006695 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006696 }
6697
6698 if (!cmd)
6699 goto unlock;
6700
Florian Grandelfffd38b2015-06-18 03:16:47 +02006701 cp = cmd->param;
6702 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006703
6704 if (status)
6705 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6706 mgmt_status(status));
6707 else
6708 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6709 mgmt_status(status), &rp, sizeof(rp));
6710
6711 mgmt_pending_remove(cmd);
6712
6713unlock:
6714 hci_dev_unlock(hdev);
6715}
6716
6717static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6718 void *data, u16 data_len)
6719{
6720 struct mgmt_cp_add_advertising *cp = data;
6721 struct mgmt_rp_add_advertising rp;
6722 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306723 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006724 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006725 u16 timeout, duration;
6726 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6727 u8 schedule_instance = 0;
6728 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006729 int err;
6730 struct mgmt_pending_cmd *cmd;
6731 struct hci_request req;
6732
6733 BT_DBG("%s", hdev->name);
6734
6735 status = mgmt_le_support(hdev);
6736 if (status)
6737 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6738 status);
6739
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006740 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6741 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6742 MGMT_STATUS_INVALID_PARAMS);
6743
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006744 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6745 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6746 MGMT_STATUS_INVALID_PARAMS);
6747
Arman Uguray24b4f382015-03-23 15:57:12 -07006748 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006749 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006750 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006751
Florian Grandelfffd38b2015-06-18 03:16:47 +02006752 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306753 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006754 */
6755 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306756 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
6757 if (flags & ~supported_flags ||
6758 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07006759 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6760 MGMT_STATUS_INVALID_PARAMS);
6761
6762 hci_dev_lock(hdev);
6763
Arman Uguray912098a2015-03-23 15:57:15 -07006764 if (timeout && !hdev_is_powered(hdev)) {
6765 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6766 MGMT_STATUS_REJECTED);
6767 goto unlock;
6768 }
6769
Arman Uguray24b4f382015-03-23 15:57:12 -07006770 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006771 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006772 pending_find(MGMT_OP_SET_LE, hdev)) {
6773 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6774 MGMT_STATUS_BUSY);
6775 goto unlock;
6776 }
6777
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006778 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6779 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006780 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006781 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6782 MGMT_STATUS_INVALID_PARAMS);
6783 goto unlock;
6784 }
6785
Florian Grandelfffd38b2015-06-18 03:16:47 +02006786 err = hci_add_adv_instance(hdev, cp->instance, flags,
6787 cp->adv_data_len, cp->data,
6788 cp->scan_rsp_len,
6789 cp->data + cp->adv_data_len,
6790 timeout, duration);
6791 if (err < 0) {
6792 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6793 MGMT_STATUS_FAILED);
6794 goto unlock;
6795 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006796
Florian Grandelfffd38b2015-06-18 03:16:47 +02006797 /* Only trigger an advertising added event if a new instance was
6798 * actually added.
6799 */
6800 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006801 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006802
Florian Grandelfffd38b2015-06-18 03:16:47 +02006803 if (hdev->cur_adv_instance == cp->instance) {
6804 /* If the currently advertised instance is being changed then
6805 * cancel the current advertising and schedule the next
6806 * instance. If there is only one instance then the overridden
6807 * advertising data will be visible right away.
6808 */
6809 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006810
Florian Grandelfffd38b2015-06-18 03:16:47 +02006811 next_instance = hci_get_next_instance(hdev, cp->instance);
6812 if (next_instance)
6813 schedule_instance = next_instance->instance;
6814 } else if (!hdev->adv_instance_timeout) {
6815 /* Immediately advertise the new instance if no other
6816 * instance is currently being advertised.
6817 */
6818 schedule_instance = cp->instance;
6819 }
Arman Uguray912098a2015-03-23 15:57:15 -07006820
Florian Grandelfffd38b2015-06-18 03:16:47 +02006821 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6822 * there is no instance to be advertised then we have no HCI
6823 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006824 */
6825 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006826 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6827 !schedule_instance) {
6828 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006829 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6830 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6831 goto unlock;
6832 }
6833
6834 /* We're good to go, update advertising data, parameters, and start
6835 * advertising.
6836 */
6837 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6838 data_len);
6839 if (!cmd) {
6840 err = -ENOMEM;
6841 goto unlock;
6842 }
6843
6844 hci_req_init(&req, hdev);
6845
Johan Hedbergf2252572015-11-18 12:49:20 +02006846 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006847
Florian Grandelfffd38b2015-06-18 03:16:47 +02006848 if (!err)
6849 err = hci_req_run(&req, add_advertising_complete);
6850
Joseph Hwang72da7b22020-03-10 09:31:50 -07006851 if (err < 0) {
6852 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6853 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07006854 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07006855 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006856
6857unlock:
6858 hci_dev_unlock(hdev);
6859
6860 return err;
6861}
6862
Arman Ugurayda9293352015-03-23 15:57:13 -07006863static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6864 u16 opcode)
6865{
6866 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006867 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006868 struct mgmt_rp_remove_advertising rp;
6869
6870 BT_DBG("status %d", status);
6871
6872 hci_dev_lock(hdev);
6873
6874 /* A failure status here only means that we failed to disable
6875 * advertising. Otherwise, the advertising instance has been removed,
6876 * so report success.
6877 */
6878 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6879 if (!cmd)
6880 goto unlock;
6881
Florian Grandel01948332015-06-18 03:16:48 +02006882 cp = cmd->param;
6883 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006884
6885 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6886 &rp, sizeof(rp));
6887 mgmt_pending_remove(cmd);
6888
6889unlock:
6890 hci_dev_unlock(hdev);
6891}
6892
6893static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6894 void *data, u16 data_len)
6895{
6896 struct mgmt_cp_remove_advertising *cp = data;
6897 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006898 struct mgmt_pending_cmd *cmd;
6899 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006900 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006901
6902 BT_DBG("%s", hdev->name);
6903
Arman Ugurayda9293352015-03-23 15:57:13 -07006904 hci_dev_lock(hdev);
6905
Johan Hedberg952497b2015-06-18 21:05:31 +03006906 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006907 err = mgmt_cmd_status(sk, hdev->id,
6908 MGMT_OP_REMOVE_ADVERTISING,
6909 MGMT_STATUS_INVALID_PARAMS);
6910 goto unlock;
6911 }
6912
Arman Ugurayda9293352015-03-23 15:57:13 -07006913 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6914 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6915 pending_find(MGMT_OP_SET_LE, hdev)) {
6916 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6917 MGMT_STATUS_BUSY);
6918 goto unlock;
6919 }
6920
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006921 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006922 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6923 MGMT_STATUS_INVALID_PARAMS);
6924 goto unlock;
6925 }
6926
Florian Grandel01948332015-06-18 03:16:48 +02006927 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006928
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006929 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006930
Florian Grandel01948332015-06-18 03:16:48 +02006931 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006932 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006933
Florian Grandel01948332015-06-18 03:16:48 +02006934 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6935 * flag is set or the device isn't powered then we have no HCI
6936 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006937 */
Florian Grandel01948332015-06-18 03:16:48 +02006938 if (skb_queue_empty(&req.cmd_q) ||
6939 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006940 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306941 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006942 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006943 err = mgmt_cmd_complete(sk, hdev->id,
6944 MGMT_OP_REMOVE_ADVERTISING,
6945 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6946 goto unlock;
6947 }
6948
6949 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6950 data_len);
6951 if (!cmd) {
6952 err = -ENOMEM;
6953 goto unlock;
6954 }
6955
Arman Ugurayda9293352015-03-23 15:57:13 -07006956 err = hci_req_run(&req, remove_advertising_complete);
6957 if (err < 0)
6958 mgmt_pending_remove(cmd);
6959
6960unlock:
6961 hci_dev_unlock(hdev);
6962
6963 return err;
6964}
6965
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006966static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6967 void *data, u16 data_len)
6968{
6969 struct mgmt_cp_get_adv_size_info *cp = data;
6970 struct mgmt_rp_get_adv_size_info rp;
6971 u32 flags, supported_flags;
6972 int err;
6973
6974 BT_DBG("%s", hdev->name);
6975
6976 if (!lmp_le_capable(hdev))
6977 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6978 MGMT_STATUS_REJECTED);
6979
6980 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6981 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6982 MGMT_STATUS_INVALID_PARAMS);
6983
6984 flags = __le32_to_cpu(cp->flags);
6985
6986 /* The current implementation only supports a subset of the specified
6987 * flags.
6988 */
6989 supported_flags = get_supported_adv_flags(hdev);
6990 if (flags & ~supported_flags)
6991 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6992 MGMT_STATUS_INVALID_PARAMS);
6993
6994 rp.instance = cp->instance;
6995 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006996 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6997 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006998
6999 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7000 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7001
7002 return err;
7003}
7004
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007005static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007006 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007007 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007008 HCI_MGMT_NO_HDEV |
7009 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007010 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007011 HCI_MGMT_NO_HDEV |
7012 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007013 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007014 HCI_MGMT_NO_HDEV |
7015 HCI_MGMT_UNTRUSTED },
7016 { read_controller_info, MGMT_READ_INFO_SIZE,
7017 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007018 { set_powered, MGMT_SETTING_SIZE },
7019 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7020 { set_connectable, MGMT_SETTING_SIZE },
7021 { set_fast_connectable, MGMT_SETTING_SIZE },
7022 { set_bondable, MGMT_SETTING_SIZE },
7023 { set_link_security, MGMT_SETTING_SIZE },
7024 { set_ssp, MGMT_SETTING_SIZE },
7025 { set_hs, MGMT_SETTING_SIZE },
7026 { set_le, MGMT_SETTING_SIZE },
7027 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7028 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7029 { add_uuid, MGMT_ADD_UUID_SIZE },
7030 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007031 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7032 HCI_MGMT_VAR_LEN },
7033 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7034 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007035 { disconnect, MGMT_DISCONNECT_SIZE },
7036 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7037 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7038 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7039 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7040 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7041 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7042 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7043 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7044 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7045 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7046 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007047 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7048 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7049 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007050 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7051 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7052 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7053 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7054 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7055 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7056 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7057 { set_advertising, MGMT_SETTING_SIZE },
7058 { set_bredr, MGMT_SETTING_SIZE },
7059 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7060 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7061 { set_secure_conn, MGMT_SETTING_SIZE },
7062 { set_debug_keys, MGMT_SETTING_SIZE },
7063 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007064 { load_irks, MGMT_LOAD_IRKS_SIZE,
7065 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007066 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7067 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7068 { add_device, MGMT_ADD_DEVICE_SIZE },
7069 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007070 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7071 HCI_MGMT_VAR_LEN },
7072 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007073 HCI_MGMT_NO_HDEV |
7074 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007075 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007076 HCI_MGMT_UNCONFIGURED |
7077 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007078 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7079 HCI_MGMT_UNCONFIGURED },
7080 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7081 HCI_MGMT_UNCONFIGURED },
7082 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7083 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007084 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007085 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007086 HCI_MGMT_NO_HDEV |
7087 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007088 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007089 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7090 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007091 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007092 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007093 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007094 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7095 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007096 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307097 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307098 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007099 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7100 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007101 { set_wideband_speech, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007102};
7103
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007104void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007105{
Marcel Holtmannced85542015-03-14 19:27:56 -07007106 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007107
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007108 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7109 return;
7110
Marcel Holtmannf9207332015-03-14 19:27:55 -07007111 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007112 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007113 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7114 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7115 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007116 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007117 } else {
7118 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7119 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007120 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007121 }
7122 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007123 case HCI_AMP:
7124 ev.type = 0x02;
7125 break;
7126 default:
7127 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007128 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007129
7130 ev.bus = hdev->bus;
7131
7132 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7133 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007134}
7135
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007136void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007137{
Marcel Holtmannced85542015-03-14 19:27:56 -07007138 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007139 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007140
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007141 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7142 return;
7143
Marcel Holtmannf9207332015-03-14 19:27:55 -07007144 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007145 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007146 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007147
Marcel Holtmannf9207332015-03-14 19:27:55 -07007148 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7149 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7150 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007151 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007152 } else {
7153 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7154 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007155 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007156 }
7157 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007158 case HCI_AMP:
7159 ev.type = 0x02;
7160 break;
7161 default:
7162 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007163 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007164
7165 ev.bus = hdev->bus;
7166
7167 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7168 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007169}
7170
Andre Guedes6046dc32014-02-26 20:21:51 -03007171/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007172static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007173{
7174 struct hci_conn_params *p;
7175
7176 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007177 /* Needed for AUTO_OFF case where might not "really"
7178 * have been powered off.
7179 */
7180 list_del_init(&p->action);
7181
7182 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007183 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007184 case HCI_AUTO_CONN_ALWAYS:
7185 list_add(&p->action, &hdev->pend_le_conns);
7186 break;
7187 case HCI_AUTO_CONN_REPORT:
7188 list_add(&p->action, &hdev->pend_le_reports);
7189 break;
7190 default:
7191 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007192 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007193 }
7194}
7195
Johan Hedberg2ff13892015-11-25 16:15:44 +02007196void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007197{
7198 struct cmd_lookup match = { NULL, hdev };
7199
Johan Hedberg2ff13892015-11-25 16:15:44 +02007200 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007201
Johan Hedberg2ff13892015-11-25 16:15:44 +02007202 hci_dev_lock(hdev);
7203
7204 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007205 restart_le_actions(hdev);
7206 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007207 }
7208
Johan Hedberg229ab392013-03-15 17:06:53 -05007209 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7210
7211 new_settings(hdev, match.sk);
7212
Johan Hedberg229ab392013-03-15 17:06:53 -05007213 if (match.sk)
7214 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007215
7216 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007217}
7218
Johan Hedberg2ff13892015-11-25 16:15:44 +02007219void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007220{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007221 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007222 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007223
Johan Hedberg229ab392013-03-15 17:06:53 -05007224 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007225
7226 /* If the power off is because of hdev unregistration let
7227 * use the appropriate INVALID_INDEX status. Otherwise use
7228 * NOT_POWERED. We cover both scenarios here since later in
7229 * mgmt_index_removed() any hci_conn callbacks will have already
7230 * been triggered, potentially causing misleading DISCONNECTED
7231 * status responses.
7232 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007233 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007234 status = MGMT_STATUS_INVALID_INDEX;
7235 else
7236 status = MGMT_STATUS_NOT_POWERED;
7237
7238 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007239
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007240 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007241 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7242 zero_cod, sizeof(zero_cod),
7243 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007244 ext_info_changed(hdev, NULL);
7245 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007246
Johan Hedberg2ff13892015-11-25 16:15:44 +02007247 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007248
7249 if (match.sk)
7250 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007251}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007252
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007253void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007254{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007255 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007256 u8 status;
7257
Johan Hedberg333ae952015-03-17 13:48:47 +02007258 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007259 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007260 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007261
7262 if (err == -ERFKILL)
7263 status = MGMT_STATUS_RFKILLED;
7264 else
7265 status = MGMT_STATUS_FAILED;
7266
Johan Hedberga69e8372015-03-06 21:08:53 +02007267 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007268
7269 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007270}
7271
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007272void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7273 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007274{
Johan Hedberg86742e12011-11-07 23:13:38 +02007275 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007276
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007277 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007278
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007279 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007280 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007281 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007282 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007283 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007284 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007285
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007286 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007287}
Johan Hedbergf7520542011-01-20 12:34:39 +02007288
Johan Hedbergd7b25452014-05-23 13:19:53 +03007289static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7290{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007291 switch (ltk->type) {
7292 case SMP_LTK:
7293 case SMP_LTK_SLAVE:
7294 if (ltk->authenticated)
7295 return MGMT_LTK_AUTHENTICATED;
7296 return MGMT_LTK_UNAUTHENTICATED;
7297 case SMP_LTK_P256:
7298 if (ltk->authenticated)
7299 return MGMT_LTK_P256_AUTH;
7300 return MGMT_LTK_P256_UNAUTH;
7301 case SMP_LTK_P256_DEBUG:
7302 return MGMT_LTK_P256_DEBUG;
7303 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007304
7305 return MGMT_LTK_UNAUTHENTICATED;
7306}
7307
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007308void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007309{
7310 struct mgmt_ev_new_long_term_key ev;
7311
7312 memset(&ev, 0, sizeof(ev));
7313
Marcel Holtmann5192d302014-02-19 17:11:58 -08007314 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007315 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007316 * to store long term keys. Their addresses will change the
7317 * next time around.
7318 *
7319 * Only when a remote device provides an identity address
7320 * make sure the long term key is stored. If the remote
7321 * identity is known, the long term keys are internally
7322 * mapped to the identity address. So allow static random
7323 * and public addresses here.
7324 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007325 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7326 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7327 ev.store_hint = 0x00;
7328 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007329 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007330
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007331 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007332 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007333 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007334 ev.key.enc_size = key->enc_size;
7335 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007336 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007337
Johan Hedberg2ceba532014-06-16 19:25:16 +03007338 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007339 ev.key.master = 1;
7340
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007341 /* Make sure we copy only the significant bytes based on the
7342 * encryption key size, and set the rest of the value to zeroes.
7343 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007344 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007345 memset(ev.key.val + key->enc_size, 0,
7346 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007347
Marcel Holtmann083368f2013-10-15 14:26:29 -07007348 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007349}
7350
Johan Hedbergcad20c22015-10-12 13:36:19 +02007351void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007352{
7353 struct mgmt_ev_new_irk ev;
7354
7355 memset(&ev, 0, sizeof(ev));
7356
Johan Hedbergcad20c22015-10-12 13:36:19 +02007357 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007358
Johan Hedberg95fbac82014-02-19 15:18:31 +02007359 bacpy(&ev.rpa, &irk->rpa);
7360 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7361 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7362 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7363
7364 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7365}
7366
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007367void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7368 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007369{
7370 struct mgmt_ev_new_csrk ev;
7371
7372 memset(&ev, 0, sizeof(ev));
7373
7374 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007375 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007376 * to store signature resolving keys. Their addresses will change
7377 * the next time around.
7378 *
7379 * Only when a remote device provides an identity address
7380 * make sure the signature resolving key is stored. So allow
7381 * static random and public addresses here.
7382 */
7383 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7384 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7385 ev.store_hint = 0x00;
7386 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007387 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007388
7389 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7390 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007391 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007392 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7393
7394 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7395}
7396
Andre Guedesffb5a8272014-07-01 18:10:11 -03007397void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007398 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7399 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007400{
7401 struct mgmt_ev_new_conn_param ev;
7402
Johan Hedbergc103aea2014-07-02 17:37:34 +03007403 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7404 return;
7405
Andre Guedesffb5a8272014-07-01 18:10:11 -03007406 memset(&ev, 0, sizeof(ev));
7407 bacpy(&ev.addr.bdaddr, bdaddr);
7408 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007409 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007410 ev.min_interval = cpu_to_le16(min_interval);
7411 ev.max_interval = cpu_to_le16(max_interval);
7412 ev.latency = cpu_to_le16(latency);
7413 ev.timeout = cpu_to_le16(timeout);
7414
7415 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7416}
7417
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007418void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7419 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007420{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007421 char buf[512];
7422 struct mgmt_ev_device_connected *ev = (void *) buf;
7423 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007424
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007425 bacpy(&ev->addr.bdaddr, &conn->dst);
7426 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007427
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007428 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007429
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007430 /* We must ensure that the EIR Data fields are ordered and
7431 * unique. Keep it simple for now and avoid the problem by not
7432 * adding any BR/EDR data to the LE adv.
7433 */
7434 if (conn->le_adv_data_len > 0) {
7435 memcpy(&ev->eir[eir_len],
7436 conn->le_adv_data, conn->le_adv_data_len);
7437 eir_len = conn->le_adv_data_len;
7438 } else {
7439 if (name_len > 0)
7440 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7441 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007442
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007443 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007444 eir_len = eir_append_data(ev->eir, eir_len,
7445 EIR_CLASS_OF_DEV,
7446 conn->dev_class, 3);
7447 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007448
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007449 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007450
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007451 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7452 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007453}
7454
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007455static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007456{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007457 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007458
Johan Hedbergf5818c22014-12-05 13:36:02 +02007459 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007460
7461 *sk = cmd->sk;
7462 sock_hold(*sk);
7463
Johan Hedberga664b5b2011-02-19 12:06:02 -03007464 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007465}
7466
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007467static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007468{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007469 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007470 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007471
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007472 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7473
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007474 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007475 mgmt_pending_remove(cmd);
7476}
7477
Johan Hedberg84c61d92014-08-01 11:13:30 +03007478bool mgmt_powering_down(struct hci_dev *hdev)
7479{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007480 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007481 struct mgmt_mode *cp;
7482
Johan Hedberg333ae952015-03-17 13:48:47 +02007483 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007484 if (!cmd)
7485 return false;
7486
7487 cp = cmd->param;
7488 if (!cp->val)
7489 return true;
7490
7491 return false;
7492}
7493
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007494void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007495 u8 link_type, u8 addr_type, u8 reason,
7496 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007497{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007498 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007499 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007500
Johan Hedberg84c61d92014-08-01 11:13:30 +03007501 /* The connection is still in hci_conn_hash so test for 1
7502 * instead of 0 to know if this is the last one.
7503 */
7504 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7505 cancel_delayed_work(&hdev->power_off);
7506 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007507 }
7508
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007509 if (!mgmt_connected)
7510 return;
7511
Andre Guedes57eb7762013-10-30 19:01:41 -03007512 if (link_type != ACL_LINK && link_type != LE_LINK)
7513 return;
7514
Johan Hedberg744cf192011-11-08 20:40:14 +02007515 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007516
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007517 bacpy(&ev.addr.bdaddr, bdaddr);
7518 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7519 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007520
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007521 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007522
7523 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007524 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007525
Johan Hedberg124f6e32012-02-09 13:50:12 +02007526 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007527 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007528}
7529
Marcel Holtmann78929242013-10-06 23:55:47 -07007530void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7531 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007532{
Andre Guedes3655bba2013-10-30 19:01:40 -03007533 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7534 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007535 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007536
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007537 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7538 hdev);
7539
Johan Hedberg333ae952015-03-17 13:48:47 +02007540 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007541 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007542 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007543
Andre Guedes3655bba2013-10-30 19:01:40 -03007544 cp = cmd->param;
7545
7546 if (bacmp(bdaddr, &cp->addr.bdaddr))
7547 return;
7548
7549 if (cp->addr.type != bdaddr_type)
7550 return;
7551
Johan Hedbergf5818c22014-12-05 13:36:02 +02007552 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007553 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007554}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007555
Marcel Holtmann445608d2013-10-06 23:55:48 -07007556void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7557 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007558{
7559 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007560
Johan Hedberg84c61d92014-08-01 11:13:30 +03007561 /* The connection is still in hci_conn_hash so test for 1
7562 * instead of 0 to know if this is the last one.
7563 */
7564 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7565 cancel_delayed_work(&hdev->power_off);
7566 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007567 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007568
Johan Hedberg4c659c32011-11-07 23:13:39 +02007569 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007570 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007571 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007572
Marcel Holtmann445608d2013-10-06 23:55:48 -07007573 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007574}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007575
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007576void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007577{
7578 struct mgmt_ev_pin_code_request ev;
7579
Johan Hedbergd8457692012-02-17 14:24:57 +02007580 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007581 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007582 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007583
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007584 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007585}
7586
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007587void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7588 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007589{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007590 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007591
Johan Hedberg333ae952015-03-17 13:48:47 +02007592 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007593 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007594 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007595
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007596 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007597 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007598}
7599
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007600void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7601 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007602{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007603 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007604
Johan Hedberg333ae952015-03-17 13:48:47 +02007605 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007606 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007607 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007608
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007609 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007610 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007611}
Johan Hedberga5c29682011-02-19 12:05:57 -03007612
Johan Hedberg744cf192011-11-08 20:40:14 +02007613int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007614 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007615 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007616{
7617 struct mgmt_ev_user_confirm_request ev;
7618
Johan Hedberg744cf192011-11-08 20:40:14 +02007619 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007620
Johan Hedberg272d90d2012-02-09 15:26:12 +02007621 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007622 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007623 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007624 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007625
Johan Hedberg744cf192011-11-08 20:40:14 +02007626 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007627 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007628}
7629
Johan Hedberg272d90d2012-02-09 15:26:12 +02007630int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007631 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007632{
7633 struct mgmt_ev_user_passkey_request ev;
7634
7635 BT_DBG("%s", hdev->name);
7636
Johan Hedberg272d90d2012-02-09 15:26:12 +02007637 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007638 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007639
7640 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007641 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007642}
7643
Brian Gix0df4c182011-11-16 13:53:13 -08007644static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007645 u8 link_type, u8 addr_type, u8 status,
7646 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007647{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007648 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007649
Johan Hedberg333ae952015-03-17 13:48:47 +02007650 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007651 if (!cmd)
7652 return -ENOENT;
7653
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007654 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007655 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007656
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007657 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007658}
7659
Johan Hedberg744cf192011-11-08 20:40:14 +02007660int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007661 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007662{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007663 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007664 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007665}
7666
Johan Hedberg272d90d2012-02-09 15:26:12 +02007667int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007668 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007669{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007670 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007671 status,
7672 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007673}
Johan Hedberg2a611692011-02-19 12:06:00 -03007674
Brian Gix604086b2011-11-23 08:28:33 -08007675int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007676 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007677{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007678 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007679 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007680}
7681
Johan Hedberg272d90d2012-02-09 15:26:12 +02007682int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007683 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007684{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007685 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007686 status,
7687 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007688}
7689
Johan Hedberg92a25252012-09-06 18:39:26 +03007690int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7691 u8 link_type, u8 addr_type, u32 passkey,
7692 u8 entered)
7693{
7694 struct mgmt_ev_passkey_notify ev;
7695
7696 BT_DBG("%s", hdev->name);
7697
7698 bacpy(&ev.addr.bdaddr, bdaddr);
7699 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7700 ev.passkey = __cpu_to_le32(passkey);
7701 ev.entered = entered;
7702
7703 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7704}
7705
Johan Hedberge1e930f2014-09-08 17:09:49 -07007706void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007707{
7708 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007709 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007710 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007711
Johan Hedberge1e930f2014-09-08 17:09:49 -07007712 bacpy(&ev.addr.bdaddr, &conn->dst);
7713 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7714 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007715
Johan Hedberge1e930f2014-09-08 17:09:49 -07007716 cmd = find_pairing(conn);
7717
7718 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7719 cmd ? cmd->sk : NULL);
7720
Johan Hedberga511b352014-12-11 21:45:45 +02007721 if (cmd) {
7722 cmd->cmd_complete(cmd, status);
7723 mgmt_pending_remove(cmd);
7724 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007725}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007726
Marcel Holtmann464996a2013-10-15 14:26:24 -07007727void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007728{
7729 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007730 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007731
7732 if (status) {
7733 u8 mgmt_err = mgmt_status(status);
7734 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007735 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007736 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007737 }
7738
Marcel Holtmann464996a2013-10-15 14:26:24 -07007739 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007740 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007741 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007742 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007743
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007744 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007745 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007746
Johan Hedberg47990ea2012-02-22 11:58:37 +02007747 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007748 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007749
7750 if (match.sk)
7751 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007752}
7753
Johan Hedberg890ea892013-03-15 17:06:52 -05007754static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007755{
Johan Hedberg890ea892013-03-15 17:06:52 -05007756 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007757 struct hci_cp_write_eir cp;
7758
Johan Hedberg976eb202012-10-24 21:12:01 +03007759 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007760 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007761
Johan Hedbergc80da272012-02-22 15:38:48 +02007762 memset(hdev->eir, 0, sizeof(hdev->eir));
7763
Johan Hedbergcacaf522012-02-21 00:52:42 +02007764 memset(&cp, 0, sizeof(cp));
7765
Johan Hedberg890ea892013-03-15 17:06:52 -05007766 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007767}
7768
Marcel Holtmann3e248562013-10-15 14:26:25 -07007769void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007770{
7771 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007772 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007773 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007774
7775 if (status) {
7776 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007777
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007778 if (enable && hci_dev_test_and_clear_flag(hdev,
7779 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007780 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007781 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007782 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007783
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007784 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7785 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007786 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007787 }
7788
7789 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007790 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007791 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007792 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007793 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007794 changed = hci_dev_test_and_clear_flag(hdev,
7795 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007796 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007797 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007798 }
7799
7800 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7801
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007802 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007803 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007804
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007805 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007806 sock_put(match.sk);
7807
Johan Hedberg890ea892013-03-15 17:06:52 -05007808 hci_req_init(&req, hdev);
7809
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007810 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7811 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007812 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7813 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007814 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007815 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007816 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007817 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007818
7819 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007820}
7821
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007822static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007823{
7824 struct cmd_lookup *match = data;
7825
Johan Hedberg90e70452012-02-23 23:09:40 +02007826 if (match->sk == NULL) {
7827 match->sk = cmd->sk;
7828 sock_hold(match->sk);
7829 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007830}
7831
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007832void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7833 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007834{
Johan Hedberg90e70452012-02-23 23:09:40 +02007835 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007836
Johan Hedberg92da6092013-03-15 17:06:55 -05007837 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7838 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7839 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007840
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007841 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007842 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7843 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007844 ext_info_changed(hdev, NULL);
7845 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007846
7847 if (match.sk)
7848 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007849}
7850
Marcel Holtmann7667da32013-10-15 14:26:27 -07007851void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007852{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007853 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007854 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007855
Johan Hedberg13928972013-03-15 17:07:00 -05007856 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007857 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007858
7859 memset(&ev, 0, sizeof(ev));
7860 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007861 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007862
Johan Hedberg333ae952015-03-17 13:48:47 +02007863 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007864 if (!cmd) {
7865 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007866
Johan Hedberg13928972013-03-15 17:07:00 -05007867 /* If this is a HCI command related to powering on the
7868 * HCI dev don't send any mgmt signals.
7869 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007870 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007871 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007872 }
7873
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007874 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7875 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007876 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007877}
Szymon Jancc35938b2011-03-22 13:12:21 +01007878
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007879static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7880{
7881 int i;
7882
7883 for (i = 0; i < uuid_count; i++) {
7884 if (!memcmp(uuid, uuids[i], 16))
7885 return true;
7886 }
7887
7888 return false;
7889}
7890
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007891static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7892{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007893 u16 parsed = 0;
7894
7895 while (parsed < eir_len) {
7896 u8 field_len = eir[0];
7897 u8 uuid[16];
7898 int i;
7899
7900 if (field_len == 0)
7901 break;
7902
7903 if (eir_len - parsed < field_len + 1)
7904 break;
7905
7906 switch (eir[1]) {
7907 case EIR_UUID16_ALL:
7908 case EIR_UUID16_SOME:
7909 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007910 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007911 uuid[13] = eir[i + 3];
7912 uuid[12] = eir[i + 2];
7913 if (has_uuid(uuid, uuid_count, uuids))
7914 return true;
7915 }
7916 break;
7917 case EIR_UUID32_ALL:
7918 case EIR_UUID32_SOME:
7919 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007920 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007921 uuid[15] = eir[i + 5];
7922 uuid[14] = eir[i + 4];
7923 uuid[13] = eir[i + 3];
7924 uuid[12] = eir[i + 2];
7925 if (has_uuid(uuid, uuid_count, uuids))
7926 return true;
7927 }
7928 break;
7929 case EIR_UUID128_ALL:
7930 case EIR_UUID128_SOME:
7931 for (i = 0; i + 17 <= field_len; i += 16) {
7932 memcpy(uuid, eir + i + 2, 16);
7933 if (has_uuid(uuid, uuid_count, uuids))
7934 return true;
7935 }
7936 break;
7937 }
7938
7939 parsed += field_len + 1;
7940 eir += field_len + 1;
7941 }
7942
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007943 return false;
7944}
7945
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007946static void restart_le_scan(struct hci_dev *hdev)
7947{
7948 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007949 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007950 return;
7951
7952 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7953 hdev->discovery.scan_start +
7954 hdev->discovery.scan_duration))
7955 return;
7956
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007957 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007958 DISCOV_LE_RESTART_DELAY);
7959}
7960
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007961static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7962 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7963{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007964 /* If a RSSI threshold has been specified, and
7965 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7966 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7967 * is set, let it through for further processing, as we might need to
7968 * restart the scan.
7969 *
7970 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7971 * the results are also dropped.
7972 */
7973 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7974 (rssi == HCI_RSSI_INVALID ||
7975 (rssi < hdev->discovery.rssi &&
7976 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7977 return false;
7978
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007979 if (hdev->discovery.uuid_count != 0) {
7980 /* If a list of UUIDs is provided in filter, results with no
7981 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007982 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007983 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7984 hdev->discovery.uuids) &&
7985 !eir_has_uuids(scan_rsp, scan_rsp_len,
7986 hdev->discovery.uuid_count,
7987 hdev->discovery.uuids))
7988 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007989 }
7990
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007991 /* If duplicate filtering does not report RSSI changes, then restart
7992 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007993 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007994 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7995 restart_le_scan(hdev);
7996
7997 /* Validate RSSI value against the RSSI threshold once more. */
7998 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7999 rssi < hdev->discovery.rssi)
8000 return false;
8001 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008002
8003 return true;
8004}
8005
Marcel Holtmann901801b2013-10-06 23:55:51 -07008006void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008007 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8008 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008009{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008010 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008011 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008012 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008013
Johan Hedberg75ce2082014-07-02 22:42:01 +03008014 /* Don't send events for a non-kernel initiated discovery. With
8015 * LE one exception is if we have pend_le_reports > 0 in which
8016 * case we're doing passive scanning and want these events.
8017 */
8018 if (!hci_discovery_active(hdev)) {
8019 if (link_type == ACL_LINK)
8020 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03008021 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03008022 return;
8023 }
Andre Guedes12602d02013-04-30 15:29:40 -03008024
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008025 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008026 /* We are using service discovery */
8027 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8028 scan_rsp_len))
8029 return;
8030 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008031
Johan Hedberg78b781c2016-01-05 13:19:32 +02008032 if (hdev->discovery.limited) {
8033 /* Check for limited discoverable bit */
8034 if (dev_class) {
8035 if (!(dev_class[1] & 0x20))
8036 return;
8037 } else {
8038 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
8039 if (!flags || !(flags[0] & LE_AD_LIMITED))
8040 return;
8041 }
8042 }
8043
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008044 /* Make sure that the buffer is big enough. The 5 extra bytes
8045 * are for the potential CoD field.
8046 */
8047 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008048 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008049
Johan Hedberg1dc06092012-01-15 21:01:23 +02008050 memset(buf, 0, sizeof(buf));
8051
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008052 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8053 * RSSI value was reported as 0 when not available. This behavior
8054 * is kept when using device discovery. This is required for full
8055 * backwards compatibility with the API.
8056 *
8057 * However when using service discovery, the value 127 will be
8058 * returned when the RSSI is not available.
8059 */
Szymon Janc91200e92015-01-22 16:57:05 +01008060 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8061 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008062 rssi = 0;
8063
Johan Hedberg841c5642014-07-07 12:45:54 +03008064 bacpy(&ev->addr.bdaddr, bdaddr);
8065 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008066 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008067 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008068
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008069 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008070 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008071 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008072
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008073 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8074 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008075 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008076 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008077
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008078 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008079 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008080 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008081
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008082 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8083 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008084
Marcel Holtmann901801b2013-10-06 23:55:51 -07008085 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008086}
Johan Hedberga88a9652011-03-30 13:18:12 +03008087
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008088void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8089 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008090{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008091 struct mgmt_ev_device_found *ev;
8092 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8093 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008094
Johan Hedbergb644ba32012-01-17 21:48:47 +02008095 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008096
Johan Hedbergb644ba32012-01-17 21:48:47 +02008097 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008098
Johan Hedbergb644ba32012-01-17 21:48:47 +02008099 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008100 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008101 ev->rssi = rssi;
8102
8103 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008104 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008105
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008106 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008107
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008108 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008109}
Johan Hedberg314b2382011-04-27 10:29:57 -04008110
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008111void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008112{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008113 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008114
Andre Guedes343fb142011-11-22 17:14:19 -03008115 BT_DBG("%s discovering %u", hdev->name, discovering);
8116
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008117 memset(&ev, 0, sizeof(ev));
8118 ev.type = hdev->discovery.type;
8119 ev.discovering = discovering;
8120
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008121 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008122}
Antti Julku5e762442011-08-25 16:48:02 +03008123
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008124static struct hci_mgmt_chan chan = {
8125 .channel = HCI_CHANNEL_CONTROL,
8126 .handler_count = ARRAY_SIZE(mgmt_handlers),
8127 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008128 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008129};
8130
8131int mgmt_init(void)
8132{
8133 return hci_mgmt_chan_register(&chan);
8134}
8135
8136void mgmt_exit(void)
8137{
8138 hci_mgmt_chan_unregister(&chan);
8139}